2013-10-23 10 views
5

私はリトルスキーマーを読み、次のコードについて混乱を感じています:Schemeで自分自身を呼び出す匿名関数のメカニズム?

((lambda (len) 
    (lambda (l) 
     (cond 
     ((null? l) 0) 
     (else 
      (+ 1 (len (cdr l))))))) 
    eternity) 

(define eternity 
    (lambda (x) 
     (eternity x))) 

コードは、空のリストを決定することである、それ以外の場合は停止しません。

"len"は再帰的ではないのはなぜですか?

+0

"len"はラムダ式のパラメータであるため、再帰型ではありません。その価値は何でもかまいません。ここは「永遠」です。また、最初の式は定義ではありません。最初の式が評価されるとき、 '永遠性 'はまだ定義されていません。 –

+0

ありがとうございます。理解しました。 – liu

答えて

5

それは(複数の評価などの危険性があるので)Lispのフォームにテキスト置換を適用することが危険なことができますが、この場合には、それはそれは一緒にどのように適合するか、このフォームを見て、見に役立つことがあります。

((lambda (len) 
    (lambda (l) 
    ...)) 
eternity) 

は、アプリケーション、つまり関数呼び出しです。呼び出される関数はlenという1つの引数をとり、1つの引数をとる別の関数lを返します。呼び出される関数はeternityで呼び出されます。呼び出しが完了すると、結果はこの関数です。

(lambda (l) 
    (cond 
    ((null? l) 0) 
    (else (+ 1 (eternity (cdr l)))))) 

は今、この関数はリストlを取り、それが空の場合、0を返します。それ以外の場合は、(cdr l)(残りのリスト)を計算し、その値でeternityを呼び出します。その結果が返されると、1が結果に追加され、それが関数全体の戻り値になります。問題は、もちろん、また

(define (eternity x) 
    (eternity x)) 

のように書くことができeternity

(define eternity 
    (lambda (x) 
    (eternity x))) 

は、単に引数xをとり、その後、xeternityを呼び出すことです。それは無限ループです。上記では、私は "返すとき"と書いたが、実際には、(eternity (cdr l))は決してが返ってくる。だから、

((lambda (len) 
    (lambda (l) 
    (cond 
     ((null? l) 0) 
     (else (+ 1 (len (cdr l))))))) 
eternity) 

は空のリストで呼び出された場合0を返し、非空のリストと無限ループに入る機能(lambda (l) …)を返す関数呼び出しです。

プログラム分析側からは、であり、これは無限ループには入りません。たとえば、文字列で呼び出すと、(cdr l)はエラーになります。

2

あなたが言うように、これは長さ関数を空のリストに対してのみ完了する部分関数として定義したものです。しかし、これはyコンビネータの部分にはまだ達していませんが、それ自体を呼び出す無名関数の例ではありません。

lは、アトムのリストであり、(lambda (len) ...)が評価されたときに返される関数の引数です。

lenは、引数として外側のラムダに渡される関数です。

外側の式は、引数としてeternityが渡されたラムダを作成します。外側のラムダは内側のラムダを評価することによって生成された関数を返します。返される関数は、eternityを引数とするものです。

コードが空のリスト(最初の部分全体をラップし、その後に'()を別の括弧で囲むことを意味する)を渡すと、もちろん0に評価されます。 lenは評価されません。

コードが空でない緯度を渡された場合、len引数を評価しようとすると、無限の再帰が得られます。

関連する問題