我正在使用haskell中实现的lambda演算。表达式:
%x.e -- lambda abstraction, like \x->e in Haskell
e e' -- application
x,y,z -- variables
succ, pred, ifzero, 0, 1, 2....
语法:
type Id = String
-- The "builtin" functions.
data Op = Succ | Pred | IfZero
deriving (Show, Ord, Eq)
-- Expressions of L
data Exp = Var Id
| Nat Integer
| Op Op
| Lam Id Exp
| App Exp Exp
deriving (Ord, Eq, Show)
还有一个将常用表示转换为Exp
的函数:
parse "%f. f 1 2" = Lam "f" App (App (Var "f") (Nat 1)) (Nat 2)`
我必须编写subst x e e'
函数,用e
代替所有" free"在(Var x)
中出现e'
。 "免"表示变量不是由周围的%
声明的。例如,在表达式
x (%x. x (%y.xz)) (%y.x)
有x
次出现5次。第一个是"免费"。第二个是%
表达式的参数,永远不会替换。第三次和第四次出现是指封闭%
表达式的参数。第五个是免费的。因此,如果我们将0
替换为x
,我们会0 (%x. x (%y.xz)) (%y.0)
。
我需要使用的是模式匹配和递归。我所能写的只是函数原型
subst :: Id -> Exp -> Exp -> Exp
subst x (App z z') (App e e') =
如果有人能给我一个如何实现这个功能的提示,那就太好了。任何帮助都非常感谢
答案 0 :(得分:1)
我想首先指出模式匹配(subst x (App z z') (App e e')
)并非详尽无遗。 (大多数)其他模式都是微不足道的,所以很容易忘记它们。我建议不要使用模式匹配第三个参数,因为如果你所做的只是把它归入第二个参数,你就不在乎它是否是App
lication或Nat
ural。
大多数递归函数的第一步是考虑案例。基本案例是什么?在这种情况下,第二个参数等于Var x
:
-- Replace x with y in a Var. If the Var is equal to x, replace
-- otherwise, leave alone.
subst x (Var a) y
| a == x = y
| otherwise = (Var a)
然后我们需要考虑步骤情况,如果它是一个应用程序,如果它是一个lambda抽象怎么办?
-- Replace x with y in an application. We just need to replace
-- x with y in z and in z', because an application doesn't
-- bind x (x stays free in z and z').
subst x (App z z') y = (App new_z new_z')
where new_z = -- Recursively call subst here.
new_z' = -- And recursively call subst here, too.
-- Replace x with y in a lambda abstraction. We *do* need to
-- check to make sure that the lambda doesn't bind x. If the
-- lambda does bind x, then there's no possibility of x being
-- free in e, and we can leave the whole lambda as-is.
subst x (Lam z e) y
| z == x = (Lam z e)
| otherwise = (Lam z new_e)
where new_e = -- Recursively call subst here.
最后,所有琐碎的案例都是一样的(我们单独留下Nat和Op,因为我们没有机会替换它们):
subst :: Id -> Exp -> Exp -> Exp
subst _ nat_or_op _ = nat_or_op