unbound-0.2.1: examples/LC-smallstep.hs
-- Untyped lambda calculus, with small-step evaluation and an example parser
{-# LANGUAGE PatternGuards
, MultiParamTypeClasses
, TemplateHaskell
, ScopedTypeVariables
, FlexibleInstances
, FlexibleContexts
, UndecidableInstances
#-}
import Control.Applicative
import Control.Arrow
import Control.Monad
import Control.Monad.Trans.Maybe
import Text.Parsec hiding ((<|>))
import qualified Text.Parsec.Token as P
import Text.Parsec.Language (haskellDef)
import Unbound.LocallyNameless
data Term = Var (Name Term)
| App Term Term
| Lam (Bind (Name Term) Term)
deriving Show
$(derive [''Term])
instance Alpha Term
instance Subst Term Term where
isvar (Var v) = Just (SubstName v)
isvar _ = Nothing
done :: MonadPlus m => m a
done = mzero
step :: Term -> MaybeT FreshM Term
step (Var _) = done
step (Lam _) = done
step (App (Lam b) t2) = do
(x,t1) <- unbind b
return $ subst x t2 t1
step (App t1 t2) =
App <$> step t1 <*> pure t2
<|> App <$> pure t1 <*> step t2
tc :: Monad m => (a -> MaybeT m a) -> (a -> m a)
tc f a = do
ma' <- runMaybeT (f a)
case ma' of
Just a' -> tc f a'
Nothing -> return a
eval :: Term -> Term
eval x = runFreshM (tc step x)
-- Some example terms
lam :: String -> Term -> Term
lam x t = Lam $ bind (string2Name x) t
var :: String -> Term
var = Var . string2Name
idT = lam "y" (var "y")
foo = lam "z" (var "y")
trueT = lam "x" (lam "y" (var "x"))
falseT = lam "x" (lam "x" (var "x"))
-- A small parser for Terms
lexer = P.makeTokenParser haskellDef
parens = P.parens lexer
brackets = P.brackets lexer
ident = P.identifier lexer
parseTerm = parseAtom `chainl1` (pure App)
parseAtom = parens parseTerm
<|> var <$> ident
<|> lam <$> (brackets ident) <*> parseTerm
runTerm :: String -> Either ParseError Term
runTerm = (id +++ eval) . parse parseTerm ""
{- example, 2 + 3 = 5:
*Main> runTerm "([m][n][s][z] m s (n s z)) ([s] [z] s (s z)) ([s][z] s (s (s z))) s z"
Right (App (Var s) (App (Var s) (App (Var s) (App (Var s) (App (Var s) (Var z))))))
-}