我正在尝试在Haskell中为lambda写下一个alpha等价函数。
data Expr = App Expr Expr | Lam Int Expr | Var Int deriving (Show,Eq)
我已经阅读了一些在线资源,但我无法将它们转换为代码。 谢谢
答案 0 :(得分:1)
因此,如果您可以通过重命名变量将一个表达式转换为另一个表达式,则两个表达式是等效的那我们怎么能抓住这个呢?主要有两种方式:
我们去找第一个
-- helper functions for association lists
type Alist a = [(a,a)]
assoc, rassoc :: Eq a => a -> Alist a -> a
assoc x ((a,b):ps) = if x == a then b else assoc x ps
rassoc x = assoc x . map (\(a,b) -> (b,a))
acons a b l = (a,b):l
(=*=) :: Expr -> Expr -> Bool
a =*= b = eq [] a b where
eq l (Lam n x) (Lam m y) = eq (acons n m l) x y
eq l (Var n) (Var m) = assoc n l == m && n == rassoc m l
eq l (App f u) (App g v) = eq l f g && eq l u v
eq l _ _ = False
这里唯一真正的微妙之处在于比较变量。要检查x
和y
是否等同于alpha,我们需要检查x
的绑定是否与y
的绑定以及y
的绑定相对应到x
的绑定。否则,我们可能会说\x.\y.x
等同于\y.\y.y
。
值得注意的是,格式错误的表达式会导致匹配失败。
以下是如何隐式执行第二个选项:
varN :: Eq a => a -> [a] -> Int
varN a xs = v 0 xs where
v n (x:xs) = if a == x then n else v (n+1) xs
a =*= b = eq [] [] a b in where
eq k l (Lam n x) (Lam m y) = eq (n:k) (m:l) x y
eq k l (Var n) (Var m) = varN n k == varN m l
eq k l (App f u) (App g v) = eq k l f g && eq k l u v
eq k l _ _ = False
希望你能看到这些是等价的