私はこのことのいくつかを自分自身に教えてきたので、次のことを正しく理解できることを願っています...
nm が言及しているように、Haskell が型付けされているという事実は、この質問にとって非常に重要です。型システムは、形成できる式を制限します。特に、ラムダ計算の最も基本的な型システムは、自己適用を禁止します。これにより、最終的に非チューリング完全言語が得られます。チューリングの完全性は、言語の追加機能 (演算子または再帰型のいずれか)として、基本型システムの上に追加されます。fix :: (a -> a) -> a
これは、Haskell でこれをまったく実装できないという意味ではありませんが、そのような実装には演算子が 1 つしかないということではありません。
アプローチ #1: here から 2 番目の例の 1 点組み合わせ論理基礎を実装し、fix
関数を追加します。
iota' :: ((t1 -> t2 -> t1)
-> ((t5 -> t4 -> t3) -> (t5 -> t4) -> t5 -> t3)
-> (t6 -> t7 -> t6)
-> t)
-> t
iota' x = x k s k
where k x y = x
s x y z = x z (y z)
fix :: (a -> a) -> a
fix f = let result = f result in result
iota'
これで、とを使って任意のプログラムを作成できますfix
。これがどのように機能するかを説明するのは少し複雑です。(編集:これは元の質問iota'
の と同じではないことに注意してください。これは、チューリング完全でもあります。プログラムがプログラムとは異なる場合です。Haskellで定義を試しました;それ型チェックを行いますが、試行すると型エラーが発生します。)λx.x S K
λx.x K S K
iota'
iota
iota = λx.x S K
k = iota (iota (iota iota))
s = iota (iota (iota (iota iota)))
アプローチ #2:型指定されていないラムダ計算の表示は、この再帰型を使用して Haskell に埋め込むことができます。
newtype D = In { out :: D -> D }
D
D
は基本的に からまでの関数を要素とする型ですD
。関数をプレーンにIn :: (D -> D) -> D
変換し、その逆を行う必要があります。したがって、 がある場合は、 を実行して自己適用できます。D -> D
D
out :: D -> (D -> D)
x :: D
out x x :: D
それを与えると、次のように書くことができます:
iota :: D
iota = In $ \x -> out (out x s) k
where k = In $ \x -> In $ \y -> x
s = In $ \x -> In $ \y -> In $ \z -> out (out x z) (out y z)
In
これには、 andからの「ノイズ」が必要out
です。Haskell は、 aD
に aを適用することを依然として禁止していますが、 andをD
使用してこれを回避できます。type の値で実際に役立つことは何もできませんが、同じパターンで有用な型を設計することはできます。In
out
D
編集: iota は基本的λx.x S K
に 、 where K = λx.λy.x
、S = λx.λy.λz.x z (y z)
. つまり、iota は 2 つの引数の関数を取り、それを S と K に適用します。つまり、最初の引数を返す関数を渡すと S が得られ、2 番目の引数を返す関数を渡すと K が得られます。 S と K は iota で書けます。しかし、チューリング完全性を得るには S と K で十分なので、おまけにチューリング完全性も得られます。必要なセレクター関数を iota で記述できることが判明したため、Turing の完全性には iota で十分です。
したがって、これにより、イオタを理解するという問題が SK 計算を理解することに軽減されます。