Unification of Methods and Functions
Antoon Pardon
apardon at forel.vub.ac.be
Wed May 26 04:16:08 EDT 2004
Op 2004-05-25, Antoon Pardon schreef <apardon at forel.vub.ac.be>:
> Op 2004-05-25, David MacQuigg schreef <dmq at gain.com>:
>> On 25 May 2004 10:30:03 GMT, Antoon Pardon <apardon at forel.vub.ac.be>
>> wrote:
>>
> 3) Higher order functions. These are functions that
> whose arguments and/or return values can be again
> functions.
>
> The typical example is a sorting function that takes
> as an argument a function that decides which of two
> elements is the smaller. By providing different
> functions (one that looks at names or one that
> looks at Id number) the same function can be used
> to sort people alphabetical or Numerical by Id.
>
> Now to go a step further. Suppose we have a lot
> of functions Fi: Each of these functions is
> defined as follows Fi(x) = i + x. Now we
> can have an other function S. S is defined as
> follows: S(a) = Fa. Now we can use S to add
> two numbers. Suppose we want to add 2 and 5.
> First we call S(2), this will result in F2.
> Then we call F2(5) which will result in 7.
> Or more directly we could call S(2)(5).
>
> Now python allows to define higher order functions.
> S would be defined as follows in python:
>
> def S(i):
>
> def Fi(x):
>
> return i + x
>
> return Fi
>
Now any normal function can be turned into a higher
order function with a related functionality. Supose
we have a function with the following signature in
python
def func(a1, a2, a3):
We can then write the higher order function as
follows:
def Hfunc(a1):
def Ifunc(a2, a3):
return func(a1, a2, a3)
return Ifunc
Now transforming a function to a higher order
equivallent is called currying and currying is
again a higher order function. In python we
write it as follows
def curry(f):
def Hf(a1):
def If(*ta):
la = (a1,) + ta
return apply(f, la)
return If
return Hf
So from now on if we have a function we can turn it
into its curried version as follows:
Hfunc = curry(func)
So now we have all we need for object oriented programming.
To illustrate I'll make a stack pseudo class. We start
with the assumption that we have the following class.
class Bare:
pass
First approach
def Stack():
st = Bare()
st.lst = []
return st
def Empty(st):
return len(st.lst) == 0
def Pop(st):
result = st.lst[-1]
del st.lst[-1]
return result
def Push(st, el):
st.lst.append(el)
stack = Stack()
Push(stack, 4)
Push(stack, 'hallo')
El = Pop(stack)
This is a strickt procedural approach. It has the disadvantages that the
procedures Empty, Pop and Push aren't very tied to the stack and that
we therefore prohibit other structures the use of the same name
We can eliminate these disadvantages as follows:
Second approach
def Stack():
def Empty(st):
return len(st.lst) == 0
def Pop(st):
result = st.lst[-1]
del st.lst[-1]
return result
def Push(st, el):
st.lst.append(el)
st = Bare()
st.lst = []
st.Empty = Empty
st.Pop = Pop
st.Push = Push
return st
stack = Stack()
stack.Push(stack, 4)
stack.Push(stack, 'hallo')
El = stack.Pop(stack)
This looks already somewhat object oriented. The problem here
is that you are essentially obligated to allways provide the
first argument twice. To eliminate this cumbersome repetition
we work with applied curried functions as methods.
Third approach
def Stack():
def Empty(st):
return len(st.lst) == 0
def Pop(st):
result = st.lst[-1]
del st.lst[-1]
return result
def Push(st, el):
st.lst.append(el)
st = Bare()
st.lst = []
st.Empty = curry(Empty)(st)
st.Pop = curry(Pop)(st)
st.Push = curry(Push)(st)
return st
stack = Stack()
stack.Push(4)
stack.Push('hallo')
El = stack.Pop()
And we now have standard python method calls. We will just
make some cosmetic changes here to have it resemble python
class conventions more.
Fourth approach
def Stack():
def __init__(self):
self.lst = []
def Empty(self):
return len(self.lst) == 0
def Pop(self):
result = self.lst[-1]
del self.lst[-1]
return result
def Push(self, el):
self.lst.append(el)
self = Bare()
__init__(self)
self.Empty = curry(Empty)(self)
self.Pop = curry(Pop)(self)
self.Push = curry(Push)(self)
return self
stack = Stack()
stack.Push(4)
stack.Push('hallo')
El = stack.Pop()
And this is more or less equivallent to:
class Stack():
def __init__(self):
self.lst = []
def Empty(self):
return len(self.lst) == 0
def Pop(self):
result = self.lst[-1]
del self.lst[-1]
return result
def Push(self, el):
self.lst.append(el)
stack = Stack()
stack.Push(4)
stack.Push('hallo')
El = stack.Pop()
--
Antoon Pardon
More information about the Python-list
mailing list