是的,我正在发布另一个答案。而且它可能仍然不是您想要的。但我认为它可能仍然有用。它在哈斯克尔。
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 ++ ")"
所以在这里我设计了一个基本的代数数据类型来表达 lambda 演算。我添加了一个简单但有效的自定义 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
在 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))))