2016-08-06 4 views
4

Pythonで単純な機能追加を行うためにカリングを使用しようとしています。私はこのカレーデコレータhereを見つけました。任意の数の変数でPythonをカリングする

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 

私はいくつかの簡単なカリー化を行うことができますので、今、これは素晴らしいです:

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

しかし、正確に三つの変数のために、この唯一の作品を。どのように多くの変数を受け入れ、結果をカレーすることができるように関数fooを書くには?私は* argsを使う単純な解決策を試しましたが、うまくいかなかったのです。

編集:私は答えを見てきましたが、それでも、以下のように実行することができます関数を記述する方法を見つけ出すことはできません。

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

@curry def foo(* arg): return sum(arg)。これを試してください –

+3

どのようにカリングはいつ止めるべきかを知っていますか? 'foo'が任意の数の引数を取ることができる場合、' foo(1,2,3) 'はそれを呼び出すか、それともカレー化しますか? –

+0

私はsum(args)を試しました。最初の呼び出しの後では機能しません.fooはintになり、再び呼び出すことができないので、本質的にcurryingは機能しません。 – Kevin

答えて

5

おそらく、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は、あなたがやろうとしていることで設計上の問題を説明しました.-カリー化された関数への呼び出しは、 "カリー化された引数を追加する"と "ロジックを呼び出す"の間で曖昧になります。これがHaskellの問題ではない理由は、言語がのすべてがと評価されているので、は区別されません。意味があるように、 "引数なしの関数x 3 "と"前述の関数への呼び出し "を返すか、それらと"整数3 "の間でさえも返します。 Pythonはそうではありません。 (たとえば、ロジックを今すぐ呼び出すことを意味するために引数のない呼び出しを使用することはできますが、それはspecial cases aren't special enoughを破棄し、実際にカリングを行わない単純なケースのために余分なペアのカッコを必要とします。 )

functools.partialは、Pythonでの関数の部分的な適用のためのすぐれたソリューションです。残念なことに、より多くの "カレー化"引数を追加するために繰り返しpartialを呼び出すことは、それほど効率的ではありません(ネストされたpartialオブジェクトがフードの下にあります)。しかし、それはずっと柔軟です。特に、特別な装飾をしていない既存の関数で使用することができます。

1

あなたはこのような自分のためfunctools.partial例と同じものを実装することができます:機能の工場ではなく、デコレータとしてcurryを考えるのは容易であろう

def curry (prior, *additional): 
    def curried(*args): 
     return prior(*(args + additional)) 
    return curried 

def add(*args): 
    return sum(args) 

x = curry(add, 3,4,5) 
y = curry(b, 100) 
print y(200) 
# 312 

を。技術的にはデコレータはすべてですが、デコレータの使用パターンは静的であり、ファクトリは操作の連鎖の一部として呼び出すと予想されます。

私はaddから始めて、か何かではありません:工場の署名は<callable>, *<args>です。そのコメントは元の投稿への問題を回避します。

0

ファクト1:可変関数に自動カリング機能を実装することは、単に不可能です。

ファクト2:カリーを探していない可能性があります。カリー化することを知るためにカリーを探していないかもしれません。あなたが必要なものの場合

が可変引数機能をカレーにする方法です、あなたは(あなた自身のスニップを使用して)以下のこれらの線に沿って何か一緒に行く必要があります。

def curryN(arity, func): 
    """curries a function with a pre-determined number of arguments""" 
    def curried(*args, **kwargs): 
     if len(args) + len(kwargs) >= arity: 
      return func(*args, **kwargs) 
     return (lambda *args2, **kwargs2: 
      curried(*(args + args2), **dict(kwargs, **kwargs2))) 
    return curried 

def curry(func): 
    """automatically curries a function""" 
    return curryN(func.__code__.co_argcount, func); 

あなたが行うことができますこの方法:

def summation(*numbers): 
    return sum(numbers); 

sum_two_numbers = curryN(2, summation) 
sum_three_numbers = curryN(3, summation) 
increment = curryN(2, summation)(1) 
decrement = curryN(2, summation)(-1) 
関連する問題