1
1
mirror of https://github.com/kanaka/mal.git synced 2024-11-13 11:23:59 +03:00
mal/elm/Eval.elm

146 lines
3.0 KiB
Elm
Raw Normal View History

module Eval exposing (..)
import Types exposing (..)
import IO exposing (IO)
2017-06-14 16:49:27 +03:00
import Env
apply : Eval a -> Env -> EvalContext a
apply f env =
f env
run : Env -> Eval a -> EvalContext a
run env e =
apply e env
withEnv : (Env -> Eval a) -> Eval a
withEnv f env =
apply (f env) env
setEnv : Env -> Eval ()
setEnv env _ =
apply (succeed ()) env
modifyEnv : (Env -> Env) -> Eval ()
modifyEnv f env =
apply (succeed ()) (f env)
succeed : a -> Eval a
succeed res env =
( env, EvalOk res )
io : Cmd Msg -> (IO -> Eval a) -> Eval a
io cmd cont env =
( env, EvalIO cmd cont )
map : (a -> b) -> Eval a -> Eval b
map f e env =
case apply e env of
( env, EvalOk res ) ->
( env, EvalOk (f res) )
( env, EvalErr msg ) ->
( env, EvalErr msg )
( env, EvalIO cmd cont ) ->
( env, EvalIO cmd (cont >> map f) )
andThen : (a -> Eval b) -> Eval a -> Eval b
andThen f e env =
case apply e env of
( env, EvalOk res ) ->
apply (f res) env
( env, EvalErr msg ) ->
( env, EvalErr msg )
( env, EvalIO cmd cont ) ->
( env, EvalIO cmd (cont >> andThen f) )
2017-06-20 18:23:00 +03:00
catchError : (String -> Eval a) -> Eval a -> Eval a
catchError f e env =
case apply e env of
( env, EvalOk res ) ->
( env, EvalOk res )
( env, EvalErr msg ) ->
apply (f msg) env
( env, EvalIO cmd cont ) ->
( env, EvalIO cmd (cont >> catchError f) )
fail : String -> Eval a
fail msg env =
( env, EvalErr msg )
2017-06-14 16:49:27 +03:00
enter : Int -> List ( String, MalExpr ) -> Eval a -> Eval a
enter frameId bound body =
withEnv
(\env ->
modifyEnv (Env.enter frameId bound)
|> andThen (always body)
2017-06-14 16:49:27 +03:00
|> andThen
(\res ->
modifyEnv (Env.leave env.currentFrameId)
|> map (always res)
2017-06-14 16:49:27 +03:00
)
)
{-| Apply f to expr repeatedly.
Continues iterating if f returns (Left eval).
Stops if f returns (Right expr).
Tail call optimized.
-}
2017-06-20 18:23:00 +03:00
runLoop : (MalExpr -> Env -> Either (Eval MalExpr) MalExpr) -> MalExpr -> Eval MalExpr
runLoop f expr env =
2017-06-20 18:23:00 +03:00
case f expr env of
Left e ->
case apply e env of
( env, EvalOk expr ) ->
runLoop f expr env
( env, EvalErr msg ) ->
( env, EvalErr msg )
( env, EvalIO cmd cont ) ->
( env, EvalIO cmd (cont >> andThen (runLoop f)) )
Right expr ->
( env, EvalOk expr )
2017-06-18 22:38:48 +03:00
fromResult : Result String a -> Eval a
fromResult res =
case res of
Ok val ->
succeed val
Err msg ->
fail msg
2017-06-18 23:21:25 +03:00
{-| Chain the left and right Eval but ignore the right's result.
-}
ignore : Eval b -> Eval a -> Eval a
ignore right left =
left
|> andThen
(\res ->
right
|> andThen (\_ -> succeed res)
)