Python 使用任意数量的变量进行柯里化 [英] Python currying with any number of variables

查看:55
本文介绍了Python 使用任意数量的变量进行柯里化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 currying 在 Python 中进行简单的函数式添加.我在这里找到了这个咖喱装饰器.

def curry(func):def curried(*args, **kwargs):如果 len(args) + len(kwargs) >= func.__code__.co_argcount:返回 func(*args, **kwargs)返回 (lambda *args2, **kwargs2:咖喱(*(args + args2), **dict(kwargs, **kwargs2)))返回咖喱@咖喱def foo(a, b, c):返回 a + b + c

现在这很棒,因为我可以做一些简单的咖喱:

<预><代码>>>>foo(1)(2, 3)6>>>富(1)(2)(3)6

但这仅适用于三个变量.我如何编写函数 foo 以便它可以接受任意数量的变量并且仍然能够对结果进行柯里化?我尝试过使用 *args 的简单解决方案,但没有奏效.

我已经查看了答案,但仍然无法弄清楚如何编写一个可以执行如下所示的函数:

<预><代码>>>>foo(1)(2, 3)6>>>富(1)(2)(3)6>>>富(1)(2)3>>>富(1)(2)(3)(4)10

解决方案

可以说,显式优于隐式:

from functools import partial定义示例(*参数):print("这是一个传递的示例函数:", args)one_bound = 部分(示例,1)two_bound = 部分(one_bound,2)two_bound(3)

@JohnKugelman 解释了您正在尝试做的设计问题 - 对柯里化函数的调用在添加更多柯里化参数"和调用逻辑"之间会产生歧义.这在 Haskell 中不是问题的原因(概念的来源)是该语言懒惰地评估所有内容,因此您可以有意义地做出区别在一个名为 x 的函数,它不接受任何参数并只返回 3"和对上述函数的调用"之间,甚至在它们和整数 3"之间.Python不是那样的.(例如,您可以使用零参数调用来表示现在调用逻辑";但这会破坏特殊情况不够特殊,并且需要一对额外的括号来表示简单的在你实际上不想做任何柯里化的情况下.)

functools.partial 是 Python 中函数部分应用的开箱即用解决方案.不幸的是,重复调用 partial 来添加更多的柯里化"参数效率不高(在引擎盖下会有嵌套的 partial 对象).但是,它更加灵活;特别是,您可以将其与没有任何特殊装饰的现有功能一起使用.

I am trying to use currying to make a simple functional add in Python. I found this curry decorator here.

def curry(func):     
    def curried(*args, **kwargs):
        if len(args) + len(kwargs) >= func.__code__.co_argcount:
            return func(*args, **kwargs)
        return (lambda *args2, **kwargs2:
            curried(*(args + args2), **dict(kwargs, **kwargs2)))
    return curried

@curry
def foo(a, b, c):
    return a + b + c

Now this is great because I can do some simple currying:

>>> foo(1)(2, 3)
6
>>> foo(1)(2)(3)
6

But this only works for exactly three variables. How do I write the function foo so that it can accept any number of variables and still be able to curry the result? I've tried the simple solution of using *args but it didn't work.

Edit: I've looked at the answers but still can't figure out how to write a function that can perform as shown below:

>>> foo(1)(2, 3)
6
>>> foo(1)(2)(3)
6
>>> foo(1)(2)
3
>>> foo(1)(2)(3)(4)
10

解决方案

Arguably, explicit is better than implicit:

from functools import partial

def example(*args):
    print("This is an example function that was passed:", args)

one_bound = partial(example, 1)
two_bound = partial(one_bound, 2)
two_bound(3)

@JohnKugelman explained the design problem with what you're trying to do - a call to the curried function would be ambiguous between "add more curried arguments" and "invoke the logic". The reason this isn't a problem in Haskell (where the concept comes from) is that the language evaluates everything lazily, so there isn't a distinction you can meaningfully make between "a function named x that accepts no arguments and simply returns 3" and "a call to the aforementioned function", or even between those and "the integer 3". Python isn't like that. (You could, for example, use a zero-argument call to signify "invoke the logic now"; but that would break special cases aren't special enough, and require an extra pair of parentheses for simple cases where you don't actually want to do any currying.)

functools.partial is an out-of-box solution for partial application of functions in Python. Unfortunately, repeatedly calling partial to add more "curried" arguments isn't quite as efficient (there will be nested partial objects under the hood). However, it's much more flexible; in particular, you can use it with existing functions that don't have any special decoration.

这篇关于Python 使用任意数量的变量进行柯里化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆