Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I uncurry a function in Python?

Recently, I have studied 'Programming language' using standard ML, and I've learned currying method(or something), so I applied it in Python. The below is simple function and currying.

def range_new(x, y):
    return [i for i in range(x, y+1)]

def curry_2(f):
    return lambda x: lambda y: f(x, y)

def uncurry_2(f):
    pass # I don't know it...

print(range_new(1, 10))
curried_range = curry_2(range_new)
countup = curried_range(1)
print(countup(10))
print(curried_range(1)(10))

The result is below. And it works well; with curry_2 we can make a new function(countup). But, then I want to make an uncurried function. However, I don't know how I can make it. How can I do it?

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
like image 528
frhyme Avatar asked Mar 20 '18 08:03

frhyme


People also ask

What is currying function in Python?

Currying is the transformation of a function with multiple arguments into a sequence of single-argument functions. That means converting a function like this f(a, b, c, ...) into a function like this f(a)(b)(c)... . If you know Python's functools. partial , then this is very similar to it.

What does Uncurry do in Haskell?

uncurry converts a curried function to a function on pairs.

What is currying in javascript stackoverflow?

The "currying" is the process of taking the function of multiple arguments and converting it into a serious of functions that each take a single argument and return a function of a single argument, or in the case of the final function, return the actual result.


2 Answers

The easiest solution is to wrap the curried function again with code that uncurries it:

def uncurry_2(f):
    return lambda x, y: f(x)(y)

uncurried_range = uncurry_2(curried_range)
print(uncurried_range(1, 10))
like image 187
Florian Brucker Avatar answered Sep 25 '22 01:09

Florian Brucker


It's not exactly good style but you can access the variables in the closure using the (maybe CPython-only) __closure__ attribute of the returned lambda:

>>> countup.__closure__[0].cell_contents
<function __main__.range_new>

This accesses the content of the innermost closure (the variable used in the innermost lambda) of your function curry_2 and thus returns the function you used there.

However in production code you shouldn't use that. It would be better to create a class (or function) for currying that supports accessing the uncurried function (which is something lambda does not provide). However some functools in Python support accessing the "decorated" function, for example partial:

>>> from functools import partial
>>> countup = partial(range_new, 1)
>>> print(countup(10))
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> countup.func
<function __main__.range_new>
like image 38
MSeifert Avatar answered Sep 23 '22 01:09

MSeifert