module Term
(VarId, Term (Var, Abs, App, Let), readsId)
where
import Parse
import Shows
type VarId = String
data Term = Var VarId
| Abs VarId Term
| App Term Term
| Let VarId Term Term
instance Show Term where
showsPrec d = showsTerm d
instance Read Term where
readsPrec d = readsTerm
readsTerm, readsAbs, readsAtomics, readsAtomic, readsVar :: Parses Term
readsTerm = readsAbs
`elseP` readsLet
`elseP` readsAtomics
readsAtomic = readsVar
`elseP` parenP readsTerm
readsAbs = lexP "\\" `thenP` (\_ ->
plusP readsId `thenP` (\xs ->
lexP "." `thenP` (\_ ->
readsTerm `thenP` (\v ->
returnP (foldr Abs v xs)))))
readsLet = lexP "let" `thenP` (\_ ->
readsId `thenP` (\x ->
lexP "=" `thenP` (\_ ->
readsTerm `thenP` (\u ->
lexP "in" `thenP` (\_ ->
readsTerm `thenP` (\v ->
returnP (Let x u v)))))))
readsAtomics = readsAtomic `thenP` (\t ->
starP readsAtomic `thenP` (\ts ->
returnP (foldl App t ts)))
readsVar = readsId `thenP` (\x ->
returnP (Var x))
readsId :: Parses String
readsId = lexicalP (isntKeyword `filterP` plusP alphaP)
where isntKeyword x = (x /= "let" && x /= "in")
showsTerm :: Int -> Shows Term
showsTerm d (Var x) = showsString x
showsTerm d (Abs x v) = showsParenIf (d>0)
(showsString "\\" . showsString x . showsAbs v)
showsTerm d (App t u) = showsParenIf (d>1)
(showsTerm 1 t . showsChar ' ' . showsTerm 2 u)
showsTerm d (Let x u v) = showsParenIf (d>0)
(showsString "let " . showsString x .
showsString " = " . showsTerm 1 u .
showsString " in " . showsTerm 0 v)
showsAbs :: Shows Term
showsAbs (Abs x t) = showsString " " . showsString x . showsAbs t
{- ELSE -}
showsAbs t = showsString ". " . showsTerm 0 t
|