Haskell Lambda Alpha 等价

Haskell Lambda Alpha Equivalence

我正在尝试在 Haskell 中为 lambda 写下一个 alpha 等价函数。

data Expr = App Expr Expr | Lam Int Expr | Var Int deriving (Show,Eq)

我已经阅读了一些在线资源,但我无法将它们转换为代码。 谢谢

因此,如果您可以通过重命名变量将一个表达式转换为另一个,则两个表达式是等价的。那么我们如何捕捉到这一点呢?主要有两种方式:

  1. 跟踪两个表达式中哪些变量名必须相互对应。
  2. (显式或隐式)转换为使用封闭范围编号而不是变量名的形式。

让我们选择第一个

-- 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

这里唯一真正微妙的是比较变量的情况。要检查 xy 是否等价于 alpha,我们需要检查 x 的绑定对应于 y 的绑定并且 y 的绑定对应x 的绑定。否则我们可能会说 \x.\y.x 是等同于 \y.\y.y.

的 alpha

还值得注意的是,格式错误的表达式将导致匹配失败。

以下是隐式执行第二个选项的方法:

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

希望你能看出这些是等价的

type SymToSym = Map String String

alphaEqHelper :: Lexp -> Lexp -> SymToSym -> SymToSym -> Bool
alphaEqHelper (Lambda lname lfunc) (Lambda rname rfunc) ltor rtol =
  alphaEqHelper lfunc rfunc (Map.insert lname rname ltor) (Map.insert rname lname rtol)
alphaEqHelper (Apply lfunc largs) (Apply rfunc rargs) ltor rtol =
  alphaEqHelper lfunc rfunc ltor rtol && alphaEqHelper largs rargs ltor rtol
alphaEqHelper (Atom lname) (Atom rname) ltor rtol
  | Map.member lname ltor && Map.member rname rtol =
    fromJust (Map.lookup lname ltor) == rname
      && fromJust (Map.lookup rname rtol) == lname
  | Map.member lname ltor || Map.member rname rtol = False
  | otherwise = lname == rname
alphaEqHelper _ _ _ _ = False

alphaEq :: Lexp -> Lexp -> Bool
alphaEq llexp rlexp =
  alphaEqHelper
    llexp
    rlexp
    Map.empty
    Map.empty