Y Combinator をHaskellで書くことは可能ですか?
それは無限に再帰的な型を持っているようです。
Y :: f -> b -> c
where f :: (f -> b -> c)
か何か。単純なわずかに因数分解された階乗でさえ
factMaker _ 0 = 1
factMaker fn n = n * ((fn fn) (n -1)
{- to be called as
(factMaker factMaker) 5
-}
「発生チェック:無限タイプを構成できません:t = t-> t2-> t1」で失敗
(Y Combinatorは次のようになります
(define Y
(lambda (X)
((lambda (procedure)
(X (lambda (arg) ((procedure procedure) arg))))
(lambda (procedure)
(X (lambda (arg) ((procedure procedure) arg)))))))
スキームで)または、より簡潔に
(λ (f) ((λ (x) (f (λ (a) ((x x) a))))
(λ (x) (f (λ (a) ((x x) a))))))
適用順および
(λ (f) ((λ (x) (f (x x)))
(λ (x) (f (x x)))))
これは、遅延バージョンのeta収縮です。
短い変数名を使用する場合。
Oh
このwikiページ および このスタックオーバーフローの回答 は私の質問に答えているようです。
後で説明します。
さて、私はそのムー型について何か面白いものを見つけました。 S = Mu Boolを考えます。
data S = S (S -> Bool)
Sをセットとして扱い、その等号を同型として扱う場合、方程式は次のようになります。
S ⇋ S -> Bool ⇋ Powerset(S)
したがって、Sはパワーセットと同型のセットのセットです。しかし、Cantorの対角引数から、Powerset(S)のカーディナリティは常に厳密にSのカーディナリティよりも大きいため、同型になることはありません。これが、固定小数点演算子なしでは不可能ではありますが、固定小数点演算子を定義できるようになった理由だと思います。
以下は、haskellでのy-combinatorの非再帰的な定義です。
newtype Mu a = Mu (Mu a -> a)
y f = (\h -> h $ Mu h) (\x -> f . (\(Mu g) -> g) x $ x)
Y Combinatorは、Haskellの型システムの基礎となる多相ラムダ計算であるHindley-Milner型を使用して型指定することはできません。型システムのルールに訴えることでこれを証明できます。
Y Combinatorに上位の型を指定して入力できるかどうかはわかりません。それは私を驚かせますが、それが不可能であるという証拠はありません。 (キーは、ラムダにバインドされたx
の適切な多相型を識別することです。)
Haskellで固定小数点演算子が必要な場合、Haskellではletバインディングに固定小数点のセマンティクスがあるため、非常に簡単に演算子を定義できます。
fix :: (a -> a) -> a
fix f = f (fix f)
これを通常の方法で使用して、関数、さらには有限または無限のデータ構造を定義できます。
固定小数点を実装するために再帰型の関数を使用することもできます。
固定小数点を使用したプログラミングに興味がある場合は、Bruce McAdamの技術レポート That About Wraps it Up を参照してください。
Y Combinatorの標準的な定義は次のとおりです。
y = \f -> (\x -> f (x x)) (\x -> f (x x))
ただし、x x
のため、Haskellでは型チェックは行われません。無限型が必要になるためです。
x :: a -> b -- x is a function
x :: a -- x is applied to x
--------------------------------
a = a -> b -- infinite type
型システムがそのような再帰型を許可すると、型チェックが決定不能になります(無限ループになりやすい)。
ただし、Y Combinatorは、タイプチェックを強制すると機能します。 unsafeCoerce :: a -> b
を使用して:
import Unsafe.Coerce
y :: (a -> a) -> a
y = \f -> (\x -> f (unsafeCoerce x x)) (\x -> f (unsafeCoerce x x))
main = putStrLn $ y ("circular reasoning works because " ++)
これは(明らかに)安全ではありません。 rampion's answer は、再帰を使用せずにHaskellで固定小数点コンビネーターを作成するより安全な方法を示しています。