How to create functors?

Steven D'Aprano steven at
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> 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 

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?


More information about the Python-list mailing list