为无名的lambda术语生成新名称

时间:2016-04-04 20:04:50

标签: haskell lambda compiler-construction interpreter lambda-calculus

在将无名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"

虽然这有效,但我认为整个namenmgenerator构造不是很优雅,我很确定它不能很好地扩展。在这种情况下是否有常用的技术或库?

非常感谢提前!

0 个答案:

没有答案