はい、別の回答を投稿しています。そして、それはまだあなたが探しているものではないかもしれません. でもそれでも使えると思います。ハスケルにあります。
data LExpr = Lambda Char LExpr
| Atom Char
| App LExpr LExpr
instance Show LExpr where
show (Atom c) = [c]
show (App l r) = "(" ++ show l ++ " " ++ show r ++ ")"
show (Lambda c expr) = "(λ" ++ [c] ++ ". " ++ show expr ++ ")"
そこで、ラムダ計算を表現するための基本的な代数データ型を作成しました。シンプルだが効果的なカスタム Show インスタンスを追加しました。
ghci> App (Lambda 'a' (Atom 'a')) (Atom 'b')
((λa. a) b)
楽しみのためにreduce
、 helper を使用した単純なメソッドを投入しreplace
ました。警告: 慎重に検討またはテストされていません。工業用には使用しないでください。特定の厄介な表現を処理できません。:P
reduce (App (Lambda c target) expr) = reduce $ replace c (reduce expr) target
reduce v = v
replace c expr av@(Atom v)
| v == c = expr
| otherwise = av
replace c expr ap@(App l r)
= App (replace c expr l) (replace c expr r)
replace c expr lv@(Lambda v e)
| v == c = lv
| otherwise = (Lambda v (replace c expr e))
それはうまくいくようですが、それは本当に私が脇道にそれているだけです。( it
in ghci は、プロンプトで評価された最後の値を指します)
ghci> reduce it
b
それでは、楽しい部分ですrotate
。したがって、最初のレイヤーをはがすだけでよいと思います。それが Lambda の場合は、識別子を保存して、非 Lambda に到達するまでドリルダウンを続けます。次に、Lambda と識別子を「最後の」場所に戻します。そもそも Lambda ではなかった場合は、何もしません。
rotate (Lambda c e) = drill e
where drill (Lambda c' e') = Lambda c' (drill e') -- keep drilling
drill e' = Lambda c e' -- hit a non-Lambda, put c back
rotate e = e
想像を絶する変数名を許してください。これを ghci 経由で送信すると、良い兆候が示されます。
ghci> Lambda 'a' (Atom 'a')
(λa. a)
ghci> rotate it
(λa. a)
ghci> Lambda 'a' (Lambda 'b' (App (Atom 'a') (Atom 'b')))
(λa. (λb. (a b)))
ghci> rotate it
(λb. (λa. (a b)))
ghci> Lambda 'a' (Lambda 'b' (Lambda 'c' (App (App (Atom 'a') (Atom 'b')) (Atom 'c'))))
(λa. (λb. (λc. ((a b) c))))
ghci> rotate it
(λb. (λc. (λa. ((a b) c))))