正如 jozefg 所说,您可以轻松地在操作之间进行转换。我将展示如何在 lambda 项的命名、de-Bruijn 和 PHOAS 表示之间进行转换。如果您绝对愿意,将其融合到解析器中相对容易,但最好先解析命名表示然后转换。
让我们假设
import Data.Map (Map)
import qualified Data.Map as M
以及 lambda 项的以下三种表示形式:
String
基于名称
data LamN = VarN Name | AppN LamN LamN | AbsN Name LamN
deriving (Eq, Show)
type Name = String
德布鲁因指数
data LamB = VarB Int | AppB LamB LamB | AbsB LamB
deriving (Eq, Show)
PHOAS
data LamP a = VarP a | AppP (LamP a) (LamP a) | AbsP (a -> LamP a)
现在是 LampP 和其他人之间的转换(双向)。请注意,这些是偏函数。如果您将它们应用于包含自由变量的 lambda 项,则您有责任传递一个合适的环境。
如何从LamN
到LamP
将环境名称映射到 PHOAS 变量。对于封闭项,环境可以为空。
lamNtoP :: LamN -> Map Name a -> LamP a
lamNtoP (VarN n) env = VarP (env M.! n)
lamNtoP (AppN e1 e2) env = AppP (lamNtoP e1 env) (lamNtoP e2 env)
lamNtoP (AbsN n e) env = AbsP (\ x -> lamNtoP e (M.insert n x env))
如何从LamB
到LamP
采用 PHOAS 变量列表的环境。可以是封闭术语的空列表。
lamBtoP :: LamB -> [a] -> LamP a
lamBtoP (VarB n) env = VarP (env !! n)
lamBtoP (AppB e1 e2) env = AppP (lamBtoP e1 env) (lamBtoP e2 env)
lamBtoP (AbsB e) env = AbsP (\ x -> lamBtoP e (x : env))
如何从“Lamp”到“LamN”
需要将潜在的自由变量实例化为其名称。获取用于生成活页夹名称的名称。应该实例化为相互不同的名称的无限列表。
lamPtoN :: LamP Name -> [Name] -> LamN
lamPtoN (VarP n) _sup = VarN n
lamPtoN (AppP e1 e2) sup = AppN (lamPtoN e1 sup) (lamPtoN e2 sup)
lamPtoN (AbsP f) (n : sup) = AbsN n (lamPtoN (f n) sup)
如何从“LamP”到“LamB”
需要将潜在的自由变量实例化为数字。采用一个偏移量,指示我们当前所在的活页夹数量。应该被实例化为0
一个封闭的术语。
lamPtoB :: LamP Int -> Int -> LamB
lamPtoB (VarP n) off = VarB (off - n)
lamPtoB (AppP e1 e2) off = AppB (lamPtoB e1 off) (lamPtoB e2 off)
lamPtoB (AbsP f) off = AbsB (lamPtoB (f (off + 1)) (off + 1))
一个例子
-- \ x y -> x (\ z -> z x y) y
sample :: LamN
sample = AbsN "x" (AbsN "y"
(VarN "x" `AppN` (AbsN "z" (VarN "z" `AppN` VarN "x" `AppN` VarN "y"))
`AppN` (VarN "y")))
通过 PHOAS 前往 de-Bruijn:
ghci> lamPtoB (lamNtoP sample M.empty) 0
AbsB (AbsB (AppB (AppB (VarB 1) (AbsB (AppB (AppB (VarB 0) (VarB 2)) (VarB 1)))) (VarB 0)))
通过 PHOAS 回到名称:
ghci> lamPtoN (lamNtoP sample M.empty) [ "x" ++ show n | n <- [1..] ]
AbsN "x1" (AbsN "x2" (AppN (AppN (VarN "x1") (AbsN "x3" (AppN (AppN (VarN "x3") (VarN "x1")) (VarN "x2")))) (VarN "x2")))