packages feed

Feval-1.0.0.1: FVL/Eval.hs

module FVL.Eval
( eval
) where

import Control.Applicative

import FVL.Algebra
import FVL.EvalAST

type EvalAlgebra = Algebra (Expr (LazyFix Expr)) (Maybe RVal)

integer_operation :: (Integer -> Integer -> Integer) -> RVal -> RVal -> Maybe RVal
integer_operation f (RInt x) (RInt y) = Just . RInt $ f x y
integer_operation _ _ _ = Nothing

boolean_operation :: (Bool -> Bool -> Bool) -> RVal -> RVal -> Maybe RVal
boolean_operation f (RBool x) (RBool y) = Just . RBool $ f x y
boolean_operation _ _ _ = Nothing

substitute :: String -> RVal -> LazyFix Expr -> LazyFix Expr
substitute _ _ (Fx' (CInt n)) = Fx' $ CInt n
substitute _ _ (Fx' (CBool b)) = Fx' $ CBool b
substitute s v (Fx' (CVar s')) = if s' == s then valueTransform v else Fx' $ CVar s'
substitute s v (Fx' (Add x y)) = Fx' $ Add (substitute s v x) (substitute s v y)
substitute s v (Fx' (Sub x y)) = Fx' $ Sub (substitute s v x) (substitute s v y)
substitute s v (Fx' (Mul x y)) = Fx' $ Mul (substitute s v x) (substitute s v y)
substitute s v (Fx' (Div x y)) = Fx' $ Div (substitute s v x) (substitute s v y)
substitute s v (Fx' (And x y)) = Fx' $ And (substitute s v x) (substitute s v y)
substitute s v (Fx' (Or x y)) = Fx' $ Or (substitute s v x) (substitute s v y)
substitute s v (Fx' (Not x)) = Fx' . Not $ substitute s v x
substitute s v (Fx' (Equal x y)) = Fx' $ Equal (substitute s v x) (substitute s v y)
substitute s v (Fx' (Less x y)) = Fx' $ Less (substitute s v x) (substitute s v y)
substitute _ _ (Fx' Empty) = Fx' Empty
substitute s v (Fx' (Cons x y)) = Fx' $ Cons (substitute s v x) (substitute s v y)
substitute s v (Fx' (If p x y))
    = Fx' $ If (substitute s v p) (substitute s v x) (substitute s v y)
substitute s v (Fx' (Function x p)) = Fx' $ if x == s
    then Function x p
    else Function x (substitute s v p)
substitute s v (Fx' (Appl f x)) = Fx' $ Appl (substitute s v f) (substitute s v x)
substitute s v (Fx' (LetRec f x p e)) = Fx' $ if f == s
    then LetRec f x p e
    else if x == s
        then LetRec f x p (substitute s v e)
        else LetRec f x (substitute s v p) (substitute s v e)
substitute s v (Fx' (Case p x l l' y)) = if l == s || l' == s
    then Fx' $ Case (substitute s v p) (substitute s v x) l l' y
    else Fx' $ Case (substitute s v p) (substitute s v x) l l' (substitute s v y)

apply :: RVal -> LazyFix Expr -> Maybe RVal
apply (RFunction x p) e = eval e >>= \v -> eval $ substitute x v p
apply _ _ = Nothing

toList :: RVal -> Maybe [RVal]
toList REmpty = Just []
toList (RCons x y) = toList y >>= \l -> Just $ x : l
toList _ = Nothing

toCons :: [RVal] -> RVal
toCons [] = REmpty
toCons (x:xs) = RCons x $ toCons xs

alg :: EvalAlgebra
alg (CInt n) = Just $ RInt n
alg (CBool b) = Just $ RBool b
alg (CVar s) = Nothing
alg (x `Add` y) = x >>= \x' -> y >>= \y' -> integer_operation (+) x' y'
alg (x `Sub` y) = x >>= \x' -> y >>= \y' -> integer_operation (-) x' y'
alg (x `Mul` y) = x >>= \x' -> y >>= \y' -> integer_operation (*) x' y'
alg (x `Div` y) = x >>= \x' -> y >>= \y' -> case y' of
    (RInt 0) -> Nothing
    _ -> integer_operation quot x' y'
alg (x `And` y) = x >>= \x' -> y >>= \y' -> boolean_operation (&&) x' y'
alg (x `Or` y) = x >>= \x' -> y >>= \y' -> boolean_operation (||) x' y'
alg (Not x) = x >>= \x' -> case x' of
    RBool b -> Just . RBool $ not b
    _ -> Nothing
alg (x `Equal` y) = x >>= \x' -> y >>= \y' -> case (x', y') of
    (RInt m, RInt n) -> Just . RBool $ m == n
    _ -> Nothing
alg (x `Less` y) = x >>= \x' -> y >>= \y' -> case (x', y') of
    (RInt m, RInt n) -> Just . RBool $ m < n
    _ -> Nothing
alg Empty = Just REmpty
alg (x `Cons` y) = x >>= \x' -> y >>= \y' -> Just $ RCons x' y'
alg (If p e1 e2) = p >>= \p' -> case p' of
    RBool r -> if r then eval e1 else eval e2
    _ -> Nothing
alg (Function x p) = Just $ RFunction x p
alg (Appl f x) = f >>= \f' -> apply f' x
alg (LetRec f x p e) =
    let e' = Fx' $ LetRec f x p (Fx' $ Appl (Fx' $ CVar f) (Fx' $ CVar x)) in
    let r = RFunction x (Fx' $ LetRec f x p e') in
    let r' = substitute f r p in eval $ substitute f (RFunction x r') e
alg (Case p x s t y) = p >>= \p' -> toList p' >>= \r -> case r of
    [] -> eval x
    (l:ls) -> let y' = substitute s l $ substitute t (toCons ls) y in eval y'

eval :: LazyFix Expr -> Maybe RVal
eval = lazyCata alg