# 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

```