Skip to content

Instantly share code, notes, and snippets.

@boukeversteegh
Last active December 17, 2015 02:09
Show Gist options
  • Save boukeversteegh/5533958 to your computer and use it in GitHub Desktop.
Save boukeversteegh/5533958 to your computer and use it in GitHub Desktop.
How to do functional programming in Python
import inspect
# Callable class to wrap functions
class F:
def __init__(self, func, *args):
self.func = func
self.args = args
# Currying
def __call__(self, *args):
try:
nargs = len(inspect.getargspec(self.func)[0])
except TypeError:
nargs = 1
dnargs = nargs - len(args) - len(self.args)
if dnargs == 0:
return self.func(*(self.args+args))
return F(self.func, *(self.args+args))
# Composition
def __mul__(f, g):
return F(lambda a: f(g(a)))
if __name__ == "__main__":
add = lambda a, b: a + b
assert add(1,2) == 3
# Turn 'add' into a fully Functional function
add = F(add)
# Still works as normally
assert add(1,2) == 3
# Now we can do currying
assert add(1)(2) == 3
assert add()(1,2) == 3
assert add()(1)(2) == 3
add_one = add(1)
add_two = add(2)
assert add_one(10) == 11
assert add_two(10) == 12
# We can compose two functions
# add_three(x) = add_one(add_two(x))
add_three = add_one * add_two
assert add_three(5) == 8
# Let's compose three functions
rsort = F(list) * reversed * sorted
assert rsort([1,5,3,2,0,4]) == [5,4,3,2,1,0]
@santiagobasulto
Copy link

This is exactly the same as functools.partial:

from functools import partial
add = lambda a, b: a + b
assert partial(add, 1)(2) == 3

@AeroNotix
Copy link

Always check for prior art.

@boukeversteegh
Copy link
Author

@santiagosulto

It's only partially the same ;) You can't do:

add = partial(lambda a, b: a+b)

and then perform currying on 'add':

add()  # TypeError: <lambda>() takes exactly 2 arguments (0 given)
add(1) # TypeError: <lambda>() takes exactly 2 arguments (1 given)

So you would need to add the partial statement each time you'd want to curry. I think that's not very elegant.

@boukeversteegh
Copy link
Author

@AeroNotix

I guess you're right. This was just the result of playing around with Python; a mental exercise if you will. I expected similar things to have been done before, but I decided to share it anyway because some people might think it's interesting.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment