How to create functors?

B

Bruno Desthuilliers

Terry Reedy a écrit :
In Python, writing

name = lambda arg: expr

instead of

def name(arg): return expr

is all negative and no positive and should be avoided.

Except that def is a statement, and as such can't be used as a named
params when calling a function expecting a callback, ie:

vroom = some_dead('parrot', name=lambda arg: exp)

(notice the 'name = lambda arg: exp' ?-)

Ok, nitpicking. Me --->[]

<g>
 
J

J. Cliff Dyer

Terry Reedy a écrit :

Except that def is a statement, and as such can't be used as a named
params when calling a function expecting a callback, ie:

vroom = some_dead('parrot', name=lambda arg: exp)

(notice the 'name = lambda arg: exp' ?-)

Which offers no added functionality over:

def name_func(arg):
return exp

vroom = some_dead('parrot', name=name_func)

except for confusion in debugging. :) (See other excessively long
threads on lambda for further discussion of the debugging headaches
caused by lambdas.

Ok, nitpicking. Me --->[]

<g>
 
P

Paul Rubin

Robert Dailey said:
I want to simply wrap a function up into an object so it can be called
with no parameters.

Nitpick: what you are asking for is called a closure. "Functor" means
something completely different. As a few other people have explained,
"print" in python 2.x is a statement rather than a function. You could
use sys.stdout.write instead of print.
 
S

Steven D'Aprano

Nitpick: what you are asking for is called a closure. "Functor" means
something completely different.


I'm glad somebody else noticed this. I would have said something about it
myself, except I wasn't entirely sure my understanding of functor is
correct. 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.:

class Functor:
def __call__(self):
return None

f = Functor()
result = f()
 
P

Paul Rubin

Steven D'Aprano said:
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. As I'm used to it, it's a feature of certain static type
systems. The notion isn't that useful in Python but you could
translate it something like this: imagine that the "list" datatype has
a couple extra operations:

# lift_value turns a normal value from a base type to a 1-element list
list.lift_value(x) = [x]

# lift_function turns a function on a base type to a higher order
# function that operates on a whole list
list.lift_function(f) = partial(map, f)

Then given a function like

def square(x): return x*x

you could say

lifted_square = list.lifted_function(square)
print lifted_square([1,2,3,4,5])

and get [1,4,9,16,25]. Similarly if you had some other type (like a
tree data structure), that type could also support a map-like
operation so you could lift functions to it (lifting a function and
applying it to a tree like [1,[2,3],4] would result in [1,[4,9],16] or
whatever).

If I remember properly, for type t to be a functor it needs the above
two lifting operations, with the property that for a given function f,

t.lifted_value(f(x)) = (t.lifted_function(f))(t.lifted_value(x))

I guess this explanation isn't going that well but basically in a
statically typed language you'd use functors to convert the signatures
of functions to versions that operate on higher types. The idea comes
from ML and is used explicitly in Haskell, and I think some of the C++
standard template library can be explained in terms of functors.

For the mathematical concept of functors and how they relate to
programming (at least Haskell's version), see:

http://en.wikibooks.org/Haskell/Category_theory
 
S

Steven D'Aprano

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:
'---'

It can also take a function (of int -> int) and return a new function
(int -> str):
.... return n+2
....'------'


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

.... if type(arg) is int:
.... return self.map1(arg)
.... else:
.... return self.map2(arg)
....'--'


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?
 
P

Paul Rubin

Steven D'Aprano said:
According to Wikipedia, functor can be used as a synonym for "function
object": ... http://en.wikipedia.org/wiki/Function_object

Hmm, I hadn't seen that usage before. I guess there's no law against
it, but it seems a bit bogus to me.
I find the Haskell page entirely opaque and unintelligible... The
Wikipedia page is a little better

I thought it was the other way around, but I've been banging my head
against Haskell on and off for the past year or so, so it could be
that the Haskell page is more intelligible if the reader already has
some familiarity with Haskell and its type system.

Here's another attempt of my own, from the mathematical perspective:
"categories" generalize the concept of structured collections of
objects. For example, groups, rings, and sets are each a type of
structured collection, so there is a category of groups (called "Grp"
since for some reason categorists like to use capitalized, abbreviated
names), a category of rings ("Rng"), and a category of sets ("Set").
Each category has a collection of objects and a collection of "arrows"
(sometimes called morphisms) which are associative relations between
objects in the category. So in the category of sets, the objects are
sets and the arrows are functions mapping one set to another. In the
category of groups, the objects are groups and the arrows are the
homeomorphisms between groups.

Functors are mappings from one category to another, that map both the
objects and the arrows. That is they are arrows on the categories of
categories.

The concepts of categories and functors came from the loftier reaches
of algebraic geometry (further in math than I ever got) in the 1950's
or so. These days they turn out to be useful in studying type systems
of programming languages, which is where most of my exposure to them
has come from.
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')

I don't think this is right. A functor (in the PL sense that I've
been describing) acts on types, not on members of types. That is,
your example turns "3" into "---", i.e. it turns a member of type
"int" into a member of type "str". A functor would be something that
acts on arbitrary types, e.g. one might turn "int" into "array of
int", and "str" into "array of str" and so forth. Another might turn
"int" into "red-black tree containing a pair of ints at each node" and
doing something similar with str. The map1 and map2 functions (I
guess it is ok to call them that) are supposed to be generic.

I guess you could have a "String" functor whose map1 function is repr
and whose map2 functor is (lambda f: lambda x,f=f: repr(f(x))) or
something like that. It would transport every type to the str type.
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.

Right.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,199
Messages
2,571,045
Members
47,643
Latest member
ashutoshjha_1101

Latest Threads

Top