8

Peter Norvig の Python IAQ を読んでいるときに、次のコード スニペットを見つけました。

def _if(test):
    return lambda alternative: \
               lambda result: \
                   [delay(result), delay(alternative)][not not test]()
def delay(f):
    if callable(f): return f
    else: return lambda: f
fact = lambda n: _if (n <= 1) (1) (lambda: n * fact(n-1))
fact(100)

これをインターネットで検索したところ、このコードはいくつかのフォーラムに掲載されていましたが、コメントした人は全員、それがどのように機能するかを理解しているようです。

私は関数型プログラミングの概念にまったく慣れていません。test が に評価された場合Truedelay(alternative)が選択されることはわかっています。しかし実際には、test が true の場合、結果が返されます。これは私には直感に反するようです。

4

2 に答える 2

5

どれどれ:

  • _if(True)alternativeが呼び出され、すぐにパラメーターを含むラムダを返します
  • alternative返されたラムダはset toで呼び出され、ラムダ1を返しますresult
  • resultラムダはresultsetで呼び出されますlambda: n * fact(n-1)
  • not not True1 に評価されます (この例は Python 2.4 時代のものです!)。delay(alternative)
  • alternative1以前に設定されていた
  • delay(1)が呼び出され、返されますlambda: 1
  • lambda: 1が呼び出されると、 が返されます1

TL/DR:1alternativeです。

 

名前付き関数のバージョン:

def _if(test):
    def then_closure(expr_if_true):
        def else_closure(expr_if_false):
            if test:
                delayed = delay(expr_if_true)
            else:
                delayed = delay(expr_if_false)
            return delayed()
        return else_closure
    return then_closure
于 2013-01-17T02:03:15.387 に答える
1

逆に通り抜けます。

fact = lambda n: _if (n <= 1) (1) (lambda: n * fact(n-1))
fact(100)

最初の関数は [ _if( 100 <= 1) ] に縮小され、[ (1) ] と [ (lambda : n * fact(n-1)) ] の 2 つの関数から選択されます。既に説明したように、True 関数は 2 番目の関数を呼び出し、False は最初の関数を呼び出します。したがって、2 番目の関数が呼び出され、ラムダが次のように評価されます。

lambda: 100 * fact(99)

この場合、有効な遅延関数は何もしないことに注意してください。プロセス全体は、fact(99) で最初からやり直します。

fact(99) =  lambda n: _if (99 <= 1) (1) (lambda: 99 * fact(98))

ここでも _if 関数呼び出しが True になり、2 番目の関数呼び出しがトリガーされ、別の fact(98) が呼び出されます。

スタックはゆっくりと構築されます。

100 * fact(99) 
100 * 99 * fact(98)
100 * 99 * 98 * fact(97)

特殊なケースは事実(1)です:

fact(1) = lambda n: _if (1 <= 1) (1) (lambda: 1 * fact(0))

_if が False になったため、最初の関数が delay に渡され、関数に変換されて呼び出され、1 が返され、スタックが解決されます。乗算が行われ、結果が得られます (100!)。

于 2013-01-17T02:12:03.647 に答える