---------------------------------------------                             -- 001
-- Funcional language with a nice abstraction                             -- 002
---------------------------------------------                             -- 003
                                                                          -- 004
                                                                          -- 005
-- variables are just names                                               -- 006
type Var = String                                                         -- 007
                                                                          -- 008
-- values are integers and functions                                      -- 009
data Value = ValInt Integer                                               -- 010
           | ValFunc (Value -> Cmpt Value)                                -- 011
                                                                          -- 012
-- final results are strings (to be printed)                              -- 013
type Result = String                                                      -- 014
                                                                          -- 015
-- only zero is false                                                     -- 016
isTrue :: Value -> Bool                                                   -- 017
isTrue (ValInt 0) = False                                                 -- 018
isTrue _ = True                                                           -- 019
                                                                          -- 020
-- continuations                                                          -- 021
type K a = a -> Result                                                    -- 022
                                                                          -- 023
                                                                          -- 024
-- a computation gets a continuation and gives a result                   -- 025
type Cmpt a = K a -> Result                                               -- 026
                                                                          -- 027
-- transforms a value into a computation                                  -- 028
unit :: a -> Cmpt a                                                       -- 029
unit x = \k -> k x                                                        -- 030
                                                                          -- 031
-- executes an unary operation on computations                            -- 032
bind :: Cmpt a -> (a -> Cmpt b) -> Cmpt b                                 -- 033
bind ca op = \k -> ca (\a -> op a k)                                      -- 034
                                                                          -- 035
-- computation error                                                      -- 036
cerror :: String -> Cmpt a                                                -- 037
cerror s k = s                                                            -- 038
                                                                          -- 039
                                                                          -- 040
-- an Environment maps variables to Values through continuations          -- 041
type Env = Var -> Cmpt Value                                              -- 042
                                                                          -- 043
                                                                          -- 044
-- An empty Environment                                                   -- 045
emptyEnv :: Env                                                           -- 046
emptyEnv v = cerror ("undefined variable " ++ v)                          -- 047
                                                                          -- 048
                                                                          -- 049
-- bind a new value in an environment                                     -- 050
bindenv :: Var -> Value -> Env -> Env                                     -- 051
bindenv var val env = \v -> if (var == v) then (unit val) else (env v)    -- 052
                                                                          -- 053
-- executes a binary operation on computations                            -- 054
op2 :: (a -> b -> Cmpt c) -> Cmpt a -> Cmpt b -> Cmpt c                   -- 055
op2 op ca cb = bind ca (\a -> bind cb (op a))                             -- 056
                                                                          -- 057
-- executes a binary integer operation on computations                    -- 058
arith :: (Integer -> Integer -> Integer) ->                               -- 059
                (Cmpt Value -> Cmpt Value -> Cmpt Value)                  -- 060
arith op = op2 op_aux                                                     -- 061
  where op_aux (ValInt i1) (ValInt i2) = unit (ValInt (op i1 i2))         -- 062
        op_aux _ _ = cerror "binary operation over non-int value"         -- 063
                                                                          -- 064
                                                                          -- 065
--------------------------------------------------------------------      -- 066
-- Abstract Syntax Tree for Expressions                                   -- 067
data Exp = ExpK Integer          -- constants                             -- 068
         | ExpVar Var            -- variables                             -- 069
         | ExpAdd Exp Exp        -- e1 + e2                               -- 070
         | ExpSub Exp Exp        -- e1 - e2                               -- 071
         | ExpMul Exp Exp        -- e1 * e2                               -- 072
         | ExpDiv Exp Exp        -- e1 / e2                               -- 073
         | ExpIf Exp Exp Exp     -- if e1 then e2 else e3                 -- 074
         | ExpApp Exp Exp        -- e1 e2                                 -- 075
         | ExpLambda Var Exp     -- \x -> e                               -- 076
         | ExpLetrec Var Var Exp Exp        -- letrec x=(\x'->e') in e    -- 077
                                                                          -- 078
-- creates a closure in given environment                                 -- 079
closure :: Var -> Exp -> Env -> Value                                     -- 080
closure v e env = ValFunc (\x -> evalExp e (bindenv v x env))             -- 081
                                                                          -- 082
                                                                          -- 083
-- Evaluates an expression in a given environment                         -- 084
evalExp :: Exp -> Env -> Cmpt Value                                       -- 085
                                                                          -- 086
evalExp (ExpK i) env = unit (ValInt i)                                    -- 087
evalExp (ExpVar v) env = env v                                            -- 088
evalExp (ExpAdd e1 e2) env = arith (+) (evalExp e1 env) (evalExp e2 env)  -- 089
evalExp (ExpSub e1 e2) env = arith (-) (evalExp e1 env) (evalExp e2 env)  -- 090
evalExp (ExpMul e1 e2) env = arith (*) (evalExp e1 env) (evalExp e2 env)  -- 091
evalExp (ExpDiv e1 e2) env = arith div (evalExp e1 env) (evalExp e2 env)  -- 092
                                                                          -- 093
evalExp (ExpIf e1 e2 e3) env =                                            -- 094
  bind (evalExp e1 env) (\b -> if isTrue b then evalExp e2 env            -- 095
                                           else evalExp e3 env)           -- 096
                                                                          -- 097
evalExp (ExpApp e1 e2) env = op2 app (evalExp e1 env) (evalExp e2 env)    -- 098
  where app (ValFunc f) vp = f vp                                         -- 099
        app _ _ = cerror "attempt to call a non-function value"           -- 100
                                                                          -- 101
evalExp (ExpLambda v e) env = unit (closure v e env)                      -- 102
                                                                          -- 103
evalExp (ExpLetrec v v' e' e) env = evalExp e env'                        -- 104
  where env' = bindenv v (closure v' e' env') env                         -- 105
                                                                          -- 106
                                                                          -- 107
---------------------------------------------------------------------------- 108
                                                                          -- 109
                                                                          -- 110
-------------------------------------------------------------------       -- 111
-- some examples                                                          -- 112
                                                                          -- 113
-- (34 + 52) or 0                                                         -- 114
exp1 = ExpIf (ExpAdd (ExpK 34) (ExpK 52)) (ExpK 43) (ExpK 4)              -- 115
                                                                          -- 116
f1 = ExpLambda "x" (ExpApp (ExpVar "x") (ExpVar "x"))                     -- 117
f2 = ExpApp f1 f1                                                         -- 118
                                                                          -- 119
f3 = ExpApp (ExpLambda "x" (ExpK 3)) f2                                   -- 120
                                                                          -- 121
                                                                          -- 122
fat4 = ExpLetrec "f"                                                      -- 123
              "x"                                                         -- 124
           (ExpIf (ExpVar "x")                                            -- 125
                  (ExpMul (ExpVar "x")                                    -- 126
                          (ExpApp (ExpVar "f")                            -- 127
                                  (ExpSub (ExpVar "x") (ExpK 1))))        -- 128
                  (ExpK 1))                                               -- 129
        (ExpApp (ExpVar "f") (ExpK 5))                                    -- 130
                                                                          -- 131
                                                                          -- 132
                                                                          -- 133
-- code to show the final value of an expression                          -- 134
main :: IO ()                                                             -- 135
main = print (evalExp fat4 emptyEnv k)                                    -- 136
  where k x = case x of                                                   -- 137
                ValInt i  -> show i                                       -- 138
                ValFunc _ -> "function"                                   -- 139
                                                                          -- 140