module Language.LambdaBase.Eval (eval,setFix,substituteInExpr) where
import Language.LambdaBase.Parser (fixityOf)
import Language.LambdaBase.Core
toExList :: forall a. Expr a -> Expr a
toExList (Expr a f) = Expr a f
toExList a = Expr [a] Prefix
toListOfEx :: forall t. Expr t -> [Expr t]
toListOfEx (Expr a _) = a
toListOfEx a = toListOfEx $ toExList a
isName :: forall t. Expr t -> Bool
isName (Name _ _ _) = True
isName _ = False
evalLambda :: (Lit a, Show a, Eq a) => Expr a -> Expr a -> Expr a
evalLambda l@(Lambda (Arg n _) _ _) to = case substituteLambda l (setFix to (fixityOf n)) of
Lambda _ e _ -> e
evalLambda _ _ = error "Can't call evalLambda on non lambda expression"
setFix :: Expr a -> Fix -> Expr a
setFix (Name x y _) f = Name x y f
setFix (Expr l _) f = Expr l f
setFix (Lambda x y _) f = Lambda x y f
setFix (Lit a _) f = Lit a f
getFix :: Expr a -> Fix
getFix (Lambda _ _ f) = f
getFix (Expr _ f) = f
getFix (Name _ _ f) = f
getFix (Lit _ f) = f
substituteLambda :: (Lit a, Show a, Eq a) => Expr a -> Expr a -> Expr a
substituteLambda (Lambda (Arg n s) ex lfix) to =
Lambda (Arg n s) ( substituteInExpr ex (Name n Naked (fixityOf n)) to ) lfix
substituteLambda _ _ = error "Can't call substituteLambda on non lambda expression"
nameEq :: Expr a -> Expr a -> Bool
nameEq (Name a b c) (Name a2 b2 c2) = (a == a2) && (b == b2) && (c == c2)
nameEq _ _ = False
nameNotEq :: Expr a -> Expr a -> Bool
nameNotEq a b = not $ nameEq a b
substituteInExpr :: (Lit a, Show a, Eq a) => Expr a -> Expr a -> Expr a -> Expr a
substituteInExpr !e !from !to =
Expr (map (helper from to) (toListOfEx e)) (getFix e)
where
helper !f !t !e = case e of
l@(Lambda (Arg nn ss) lex llfix) -> if nameNotEq (Name nn Naked (fixityOf nn)) f then Lambda (Arg nn ss) (substituteInExpr lex from to) llfix else l
Expr ne efix -> Expr (map (helper f t) ne) efix
ne -> if nameEq e f then t else ne
eval :: (Lit a, Show a, Eq a) => Expr a -> Expr a
eval !(Expr ( x : inf : xs ) fix) | getFix inf == Infix =
eval $ Expr ( (setFix inf Prefix) : (setFix x Prefix) : xs ) fix
eval !n@(Name _ _ _) = case toLit n of
Nothing -> n
Just r -> Lit r Prefix
eval !e@(Expr ( n@(Name x t fi) : xs ) fix) = case toLit n of
Nothing -> e
Just r -> eval $ Expr ( (Lit r fi) : xs ) fix
eval !(Expr ([a]) fix) =
eval $ setFix a fix
eval !(Expr ((Expr e fix2):xs) fix) =
eval $ Expr ( e ++ xs ) fix
eval !(Expr ( l@(Lambda (Arg _ Strict) _ _) : a : xs ) fix) | getFix a /= LateInfix =
eval $ Expr ( a : (setFix l LateInfix) : xs ) fix
eval !(Expr ( l@(Lambda (Arg _ Lazy) _ _) : a : xs ) fix) | getFix a /= LateInfix =
eval $ Expr ( (evalLambda l (setFix a Prefix)) : xs ) fix
eval !(Expr ( a : (l@(Lambda _ _ _)) : xs ) fix) | getFix l == LateInfix =
eval $ Expr ( (evalLambda l (setFix a Prefix)) : xs ) fix
eval !(Expr ( a1@(Lit lit _) : a2@(Expr _ _) : xs ) fix) | getEVS lit == Strict =
eval ( Expr ( a2 : (setFix a1 LateInfix) : xs ) fix )
eval !(Expr ( x : inf : xs ) fix) | getFix inf == LateInfix =
eval $ Expr ( (setFix inf Prefix) : (setFix x Prefix) : xs ) fix
eval !e@(Expr ( (Lit x _) : (Name y t fi) : xs ) fix) = case toLit (Name y t fi) of
Nothing -> e
Just r -> eval ( Expr (( apply x r) : xs) fix )
eval !(Expr ( (Lit !x _) : (Lit !y _) : xs ) fix) =
eval ( Expr ((apply x y) : xs) fix )
eval !(Expr ( (Lit x _) : y : xs ) fix) =
eval $ Expr ((apply x (fromExpr y)) : xs) fix
eval !x = x