レイジーラケットのようなレイジー言語では、通常のオーダーバージョンを使用できますが、Schemeのようなアプリケーションプログラミング言語では使用できません。彼らは無限ループに入ります。
Yの応用的バージョンは、多くの場合、Zコンビネータと呼ばれる:
(define Z
(lambda (f)
((lambda (g) (g g))
(lambda (g)
(f (lambda args (apply (g g) args)))))))
さて、これが適用されるときに起こる最初の事は(g g)
であり、あなたはいつもそれの体の拡大にアプリケーション全体を置き換えることができますので、私は本当に何も変わっていない
(define Z
(lambda (f)
((lambda (g)
(f (lambda args (apply (g g) args))))
(lambda (g)
(f (lambda args (apply (g g) args)))))))
:関数の本体は、に書き換え得ることができます。まったく同じコードを実行するだけのコードです。このバージョンでは、複数の引数関数をサポートするためにapply
が使用されています。
(define ackermann
(lambda (m n)
(cond
((= m 0) (+ n 1))
((= n 0) (ackermann (- m 1) 1))
(else (ackermann (- m 1) (ackermann m (- n 1)))))))
(ackermann 3 6) ; ==> 509
これは、このようZ
で行うことができます:実装がまったく同じで、違いは、それ自体への参照が処理される方法である
((Z (lambda (ackermann)
(lambda (m n)
(cond
((= m 0) (+ n 1))
((= n 0) (ackermann (- m 1) 1))
(else (ackermann (- m 1) (ackermann m (- n 1))))))))
3
6) ; ==> 509
お知らせアッカーマン関数を想像してみてください。
EDIT
だから、評価が遅れる方法を求めています。あなたは、これはあなたがそれを(f (g g))
でf
を適用することができます前に、それが(g g)
たを評価する必要があるので、Yは決して戻らないことに気づくでしょう引数を指定して適用されるかを見てみると
(define Y
(lambda (f)
((lambda (g) (g g))
(lambda (g) (f (g g))))))
:まあ、通常のオーダーのバージョンは次のようになります今度は(f (g g))
などを評価します。すぐに(g g)
は適用されません。 (g g)
は関数になるので、f
に実際の関数を生成して適用する関数を与えるだけです。 add1
の機能をお持ちの場合は、代わりに使用できるラッパー(lambda (x) (add1 x))
を作成すると動作します。同じように(lambda args (apply (g g) args))
は(g g)
と同じで、置換ルールを適用するだけで表示されます。ここでのヒントは、実際に使用されるまで、各ステップでの計算を効果的に停止することです。
伝統的なYコンビネータは適用的な注文評価では機能しないため、できません。 – user2357112
'Y≡(λy。(λx.y(xx))(λx.y(xx)))'バージョンはレイジー評価を前提としています。関数の評価を遅らせる1つの方法は、関数表現 'e'を'(lambda(arg)(e arg)) 'にラップすることです。この場合、関数式 '(手続き手続き)'は ' (ラムダ(arg)((手続き手続き)arg)) '。 \t \t \t(+イテレーション(( \t \t(ISZERO反復) \t((REC手順の繰り返しを定義する) ' :私はこのような0からnまでの数字を追加するために、再帰的加算機能を持っているので、もし –
@AlexKnauthプロシージャ( - 反復1))) \t) ) ' スキームでY-コンビネータを使用するにはどうすればよいですか? –