How to create functors?

Steven D'Aprano steven at REMOVE.THIS.cybersource.com.au
Thu Aug 20 11:25:48 CEST 2009


On Thu, 20 Aug 2009 01:36:14 -0700, Paul Rubin wrote:

> Steven D'Aprano <steven at REMOVE.THIS.cybersource.com.au> writes:
>> As near as I can tell, a functor is just an object which is callable
>> like a function without actually being implemented as a function, e.g.:
> 
> No it's not anything like that either, at least as I'm used to the term
> in programming or in mathematics.  Maybe it's used other ways though. 

According to Wikipedia, functor can be used as a synonym for "function 
object":

http://en.wikipedia.org/wiki/Function_object

which is what I was thinking of. So it seems there are at least two 
meanings for the word, neither of which seems to apply to this thread :)



> As I'm used to it, it's a feature of certain static type systems.  The
> notion isn't that useful in Python 

I find the Haskell page entirely opaque and unintelligible. Well, perhaps 
not *entirely* opaque, but pretty close: it assumes a mathematical 
sophistication that I don't think I even had when I was getting my maths 
degree, let alone can remember two decades later. (Pity the poor VB 
coders wondering what Haskell is good for...) The Wikipedia page is a 
little better, but it's section on Examples is laughable -- the examples 
are as unintelligible to this reader as the description before them.


But let me try an example to see if I've got it right:


class Int2StrFunctor:
    def map1(self, n):
        if type(n) is not int:
            raise TypeError('argument must be an int')
        return "-"*n
    def map2(self, f):
        if type(f) is not type(lambda: None):
            raise TypeError('argument must be a function')
        # assume f takes an int, and returns another int
        def inner(n):
            return self.map1(f(n))
        return inner


The functor can take an int and return a string:

>>> F = Int2StrFunctor()  # F is a functor
>>> F.map1(3)
'---'

It can also take a function (of int -> int) and return a new function 
(int -> str):

>>> def myfunc(n):
...     return n+2
...
>>> f = F.map2(myfunc)
>>> f(3)
'-----'
>>> f(4)
'------'


There's nothing special about the methods map1() and map2(), I could call 
them anything I like, or even do this:


>>> def __call__(self, arg):
...     if type(arg) is int:
...             return self.map1(arg)
...     else:
...             return self.map2(arg)
...
>>> Int2StrFunctor.__call__ = __call__
>>>
>>> F(2)
'--'
>>> F(myfunc)(0)
'--'


There are some technical restrictions on functors, relating to the sorts 
of functions and types (strictly "categories") they can accept, 
presumably to make them mathematically well-behaved.


Have I got it correct?


-- 
Steven



More information about the Python-list mailing list