我想使用此数据定义来定义 Alpha 等价
type Sym = Char
data Exp = Var Sym | App Term Exp | Lam Sym Exp
deriving (Eq, Read, Show)
做这个的最好方式是什么?
一种方法是将名称转换为 De Bruijn 索引,例如0
指的是由最内层封闭 lambda 绑定的变量,1
下一个封闭的 lambda,依此类推。所以而不是absolute名称,你使用relative索引,免费为您提供 alpha 等价和避免捕获替换:
type Sym = Char
data Exp = Var Sym | App Exp Exp | Lam Sym Exp
deriving (Eq, Read, Show)
type Ind = Int
data Exp' = Var' Ind | App' Exp' Exp' | Lam' Exp'
deriving (Eq, Read, Show)
要进行转换,您只需保留一个环境范围内的名称:
db :: Exp -> Exp'
db = go []
where
-- If we see a variable, we look up its index in the environment.
go env (Var sym) = case findIndex (== sym) env of
Just ind -> Var' ind
Nothing -> error "unbound variable"
-- If we see a lambda, we add its variable to the environment.
go env (Lam sym exp) = Lam' (go (sym : env) exp)
-- The other cases are straightforward.
go env (App e1 e2) = App' (go env e1) (go env e2)
现在,alpha 等价很简单:
alphaEq x y = db x == db y
-- or:
alphaEq = (==) `on` db
例子:
-- λx.x ~ λy.y
Lam 'x' (Var 'x') `alphaEq` Lam 'y' (Var 'y') == True
-- λx.λy.λz.xz(yz)
s1 = Lam 'x' $ Lam 'y' $ Lam 'z'
$ Var 'x' `App` Var 'z' `App` (Var 'y' `App` Var 'z')
-- λa.λb.λc.ac(bc)
s2 = Lam 'a' $ Lam 'b' $ Lam 'c'
$ Var 'a' `App` Var 'c' `App` (Var 'b' `App` Var 'c')
-- λa.λb.λc.ab(ac)
s3 = Lam 'a' $ Lam 'b' $ Lam 'c'
$ Var 'a' `App` Var 'b' `App` (Var 'a' `App` Var 'c')
s1 `alphaEq` s2 == True
s1 `alphaEq` s3 == False
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)