Functional composition in python
lambdadmitry at gmail.com
Sun Aug 29 04:54:13 CEST 2010
On Aug 29, 5:14 am, Steven D'Aprano <st... at REMOVE-THIS-
> On Sat, 28 Aug 2010 21:30:39 +0400, Dmitry Groshev wrote:
> > Hello all. Some time ago I wrote a little library:
> >http://github.com/si14/python-functional-composition/, inspired by
> > modern functional languages like F#. In my opinion it is quite useful
> > now, but I would like to discuss it.
> > An example of usage:
> > import os
> > from pyfuncomp import composable, c, _
> > def comment_cutter(s):
> > t = s.find("#")
> > return s if t < 0 else s[0:t].strip()
> > @composable #one can use a decorator to make a composable function
> > def empty_tester(x):
> > return len(x) > 0 and x != "#"
> Why do you need a decorator to make a composable function? Surely all
> functions are composable -- it is the nature of functions that you can
> call one function with the output of another function.
> > path_prefix = "test"
> > config_parser = (c(open) >> #or use a transformer function
> > c(str.strip).map >> #"map" acts like a function modifier
> > c(comment_cutter).map >>
> > empty_tester.filter >> #so does "filter"
> > c(os.path.join)[path_prefix, _].map) #f[a, _, b] is
> > used to make a partial.
> > #f[a, foo:bar,
> > baz:_] is also correct
> > print config_parser("test.txt")
> > print (c("[x ** %s for x in %s]")[2, _] << c(lambda x: x * 2).map)([1,
> > 2, 3])
> > Any suggestions are appreciated.
> Did you expect us to guess what the above code would do? Without showing
> the output, the above is just line noise.
> What does c() do? What does compose() do that ordinary function
> composition doesn't do? You say that "map" acts as a function modifier,
> but don't tell us *what* it modifies or in what way. Same for filter.
> So anyone not familiar with C syntax, the use of << is just line noise.
> You need to at say what you're using it for.
Yep, it's my mistake. I thought this syntax is quite intuitive. Here
is some explanations in code:
return x * 2
return x + 3
return (-1) * x
return a + 
def sqrsum(x, y):
return x ** 2 + y ** 2
print f1(2) #4
print f2(2) #5
print (f1 << f2 << f1)(2) #14
print (f3 >> f2)(2) #1
print (f2 >> f3)(2) #-5
print (c(float) << f1 << f2)(4) #14.0
print (sqrsum[_, 1] << f1)(2) #17
print (sqrsum[_, _].map)([1, 2, 3, 4, 5]) #[2, 8, 18, 32, 50]
print (c(lambda x: x * 2).map >> c("[x * %s for x in %s]")[3, _])([1,
2, 3]) #[6, 12, 18]
Generally, f1 >> f2 means "lambda x: f2(f1(x))" or "pass the result of
f1 to f2". But in python function can return only one value, so a
composable function should be a function of one argument. So some form
of making partial is needed, and here comes a
f[a, b, _] notation, which means "substitute 3rd argument of f, first
twos are a and b". Finally, we need some form of syntactic sugar for
this: c(map)[c(f),_], so we have a "map" modifier, which transforms
function F to an isomorphism or mapping between lists. For example,
c(lambda x: x * 2).map is equal to lambda x: map(lambda y: y * 2, x).
"Filter" modifier is the same thing for boolean functions.
>What does c() do? What does compose() do that ordinary function
>composition doesn't do?
I need c() or composable() to make an objects with overloaded
All in all, all this stuff is just a syntactic sugar for nested
functions, maps and filters, which brings a new semantics for old
operators (so one can call it edsl).
More information about the Python-list