module Untyped.Term (
Term(..)
, Program
, (@=)
, subterms
, variables
, freeVariables
, freeIn
, notFreeIn
, isUnitVal
, isNatVal
, isBoolVal
, isAbsVal
, isVal
, natFromInt
, abstract
, apply
, (|->)
, (@>)
) where
import Sidekick ( passAny )
import List ( union, (\\) )
data Term = TmUnit
| TmTrue
| TmFalse
| TmIf Term Term Term
| TmZero
| TmSucc Term
| TmPred Term
| TmIsZero Term
| TmVar String
| TmAbs String Term
| TmApp Term Term
| TmStop
| TmLoop
deriving (Eq, Show)
type Program = [Term]
natFromInt :: Integral t => t -> Term
natFromInt 0 = TmZero
natFromInt (n + 1) = TmSucc (natFromInt n)
natFromInt _ = error "Negative nat?!"
abstract :: Term -> Term -> Term
abstract (TmVar x) t = TmAbs x t
abstract _ _ = error "can only abstract variable terms"
apply :: [Term] -> Term
apply [] = TmUnit
apply ts = foldl1 TmApp ts
(@=) :: Term -> Term -> Bool
t @= s = if t == s then True else case (t, s) of
( t1 `TmApp` t2 , s1 `TmApp` s2 ) -> t1 @= s1 && t2 @= s2
( TmSucc t' , TmSucc s' ) -> t' @= s'
( TmPred t' , TmPred s' ) -> t' @= s'
( TmIsZero t' , TmPred s' ) -> t' @= s'
( TmAbs x t' , TmAbs y s' ) -> t' @= (y @> x) s'
_________________________________ -> False
valueChecks :: [Term -> Bool]
valueChecks = [isUnitVal, isBoolVal, isNatVal, isAbsVal]
isUnitVal :: Term -> Bool
isUnitVal TmUnit = True
isUnitVal _ = False
isBoolVal :: Term -> Bool
isBoolVal TmTrue = True
isBoolVal TmFalse = True
isBoolVal _ = False
isNatVal :: Term -> Bool
isNatVal TmZero = True
isNatVal (TmSucc t) = isNatVal t
isNatVal _ = False
isAbsVal :: Term -> Bool
isAbsVal TmAbs {} = True
isAbsVal _ = False
isVal :: Term -> Bool
isVal = passAny valueChecks
subterms :: Term -> [Term]
subterms term = case term of
TmVar x -> [term]
TmAbs _ t -> term : subterms t
t1 `TmApp` t2 -> term : (foldl1 union $ map subterms [t1, t2])
TmIf t t1 t2 -> term : (foldl1 union $ map subterms [t, t1, t2])
TmSucc t -> term : subterms t
TmPred t -> term : subterms t
TmIsZero t -> term : subterms t
_____________ -> [term]
variables :: Term -> [String]
variables term = case term of
TmVar x -> [x]
TmAbs _ t -> variables t
t1 `TmApp` t2 -> foldl1 union $ map variables [t1, t2]
TmIf t t1 t2 -> foldl1 union $ map variables [t, t1, t2]
TmSucc t -> variables t
TmPred t -> variables t
TmIsZero t -> variables t
_____________ -> []
freeVariables :: Term -> [String]
freeVariables term = case term of
TmVar x -> [x]
TmAbs x t -> (freeVariables t) \\ [x]
t1 `TmApp` t2 -> foldl1 union $ map freeVariables [t1, t2]
TmIf t t1 t2 -> foldl1 union $ map freeVariables [t, t1, t2]
TmSucc t -> freeVariables t
TmPred t -> freeVariables t
TmIsZero t -> freeVariables t
_____________ -> []
freeIn :: String -> Term -> Bool
x `freeIn` t = x `elem` (freeVariables t)
notFreeIn :: String -> Term -> Bool
x `notFreeIn` t = not (x `freeIn` t)
niceNames :: [String]
niceNames = ["x", "y", "z"]
niceNamesPrimed :: [String]
niceNamesPrimed = zipWith (++) names decorators
where names = cycle niceNames
decorators = [ replicate n '\'' | n <- [0..]]
niceNamesIndexed :: [String]
niceNamesIndexed = zipWith (++) names decorators
where names = cycle niceNames
decorators = map show [ n `div` (length niceNames) | n <- [0..] ]
hartogs :: [String] -> String
hartogs taken = head $ dropWhile (`elem` taken) niceNamesIndexed
(|->) :: String -> Term -> Term -> Term
(x |-> s) term = case term of
TmVar y -> if x == y then s else term
TmSucc t -> TmSucc t' where t' = (x |-> s) t
TmPred t -> TmPred t' where t' = (x |-> s) t
TmIsZero t -> TmIsZero t' where t' = (x |-> s) t
t1 `TmApp` t2 -> t1' `TmApp` t2' where [t1', t2'] = map (x |-> s) [t1, t2]
TmIf t t1 t2 -> TmIf t' t1' t2' where [t', t1', t2'] = map (x |-> s) [t, t1, t2]
TmAbs y t
| x == y -> term
| y `notFreeIn` s -> TmAbs y ((x |-> s) t)
| otherwise -> (x |-> s) $ (y @> w) term
where
w = hartogs usedvars
usedvars = freeVariables s `union` variables t
___________________ -> term
(@>) :: String -> String -> Term -> Term
(x @> w) term = case term of
TmSucc t -> TmSucc t' where t' = (x @> w) t
TmPred t -> TmPred t' where t' = (x @> w) t
TmIsZero t -> TmIsZero t' where t' = (x @> w) t
t1 `TmApp` t2 -> t1' `TmApp` t2' where [t1', t2'] = map (x @> w) [t1, t2]
TmIf t t1 t2 -> TmIf t' t1' t2' where [t', t1', t2'] = map (x @> w) [t, t1, t2]
TmVar y -> if (x == y) then (TmVar w) else term
TmAbs y t -> if (x == y) then (TmAbs w t') else (TmAbs y t')
where t' = (x @> w) t
_____________ -> term