在将无名lambda术语转换为命名术语时,是否存在一些用于生成新名称的常用技术或库?
这就是我提出的(最小的例子是基于school of haskell的表示):
{-# LANGUAGE FlexibleInstances #-}
module Main where
import Control.Monad.Reader
import Data.List ((\\))
-- named terms -----------------------------------------------------------------
infixl 9 :@
infixr 0 :!
data Lambda a =
Var a
| (Lambda a) :@ (Lambda a)
| a :! (Lambda a)
deriving Show
-- nameless terms --------------------------------------------------------------
newtype Scope a = Scope (Exp a)
deriving (Eq, Show, Read)
infixl 9 :$
data Exp a =
F a
| B !Int
| (Exp a) :$ (Exp a)
| L (Scope a)
deriving (Eq, Show)
abstract :: Eq a => a -> Exp a -> Scope a
abstract name expr = Scope $ absName 0 expr where
absName distance (F name') | name == name' = B distance
| otherwise = F name'
absName distance (B index) = B index
absName distance (fun :$ arg) = absName distance fun :$ absName distance arg
absName distance (L (Scope body)) = L $ Scope $ absName (succ distance) body
instantiate :: Exp a -> Scope a -> Exp a
instantiate ersatz (Scope body) = replace 0 body where
replace distance (B index) | index == distance = ersatz
| otherwise = B index
replace distance (F name) = F name
replace distance (fun :$ arg) = replace distance fun :$ replace distance arg
replace distance (L (Scope body)) = L $ Scope $ replace (succ distance) body
-- unnaming and naming ---------------------------------------------------------
unname :: Eq a => Lambda a -> Exp a
unname (Var a) = F a
unname (fun :@ arg) = unname fun :$ unname arg
unname (n :! body) = L (abstract n (unname body))
name :: (Eq a, Generator a) => Exp a -> Lambda a
name exp = runReader (nm exp) []
nm :: (Eq a, Generator a) => Exp a -> Reader [a] (Lambda a)
nm (F a) = return $ Var a
nm (fun :$ arg) = (:@) <$> nm fun <*> nm arg
nm (L scope) = do
used <- ask
let fresh = generate used
undefined
local (fresh:) ((fresh :!) <$> nm (instantiate (F fresh) scope))
type Gen a = [a]
class Eq a => Generator a where
generator :: Gen a
generate :: [a] -> a
generate used = head (generator \\ used)
instance Generator [Char] where
generator = [ [i] | i <- ['a'..'z']] ++ [i: show j | j <- [1..], i <- ['a'..'z']]
-- test data -------------------------------------------------------------------
s = "f" :! "g" :! "x" :! (Var "f" :@ Var "x") :@ (Var "g" :@ Var "x")
k = "x" :! "y" :! Var "x"
i = "x" :! Var "x"
虽然这有效,但我认为整个name
,nm
,generator
构造不是很优雅,我很确定它不能很好地扩展。在这种情况下是否有常用的技术或库?
非常感谢提前!