data Expr = Num Integer | Var Name | Add Expr Expr | Mul Expr Expr type Name = String
eval :: [(Name,Integer)] -> Expr -> Integer
data Expr = Num Integer
| Var Name
| Add Expr Expr
| Mul Expr Expr
| Equal Expr Expr -- new
data Value = N Integer | B Bool
eval :: [(Name,Value)] -> Expr -> Value
data Value = N Integer | B Bool | E String
eval :: [(Name,Value)] -> Expr -> Value
eval
eval :: Env -> Expr -> Maybe Value
\ x -> e
(\f -> \x -> f (f x)) (\n -> 2*n) 1
data Expr = Num Integer | Var Name | Add Expr Expr | Mul Expr Expr | Equal Expr Expr | App Expr Expr -- new | Lambda Name Expr -- new
Integer
Bool
data Value = N Integer | B Bool | F (Value->Value) | E String
eval env (App fun arg) = apply (eval env fun) (eval env arg)
eval env (Lambda x body) = F (\ v -> eval ((x:v):env) body)
apply :: Value -> Value -> Value
apply (F f) v = f v
apply _ _ = E "non-function applied to an argument"
twice = \ f -> \ x -> f (f x)
> double = \ x -> 2*x
> twice double x
4
initial_env = [("false",B False), ("true",B True), ("if",(...)), ("pred",(...))]
fac n = if n==0 then 1 else n*fac (n-1)
fix f = f (fix f)
fac
fac = fix (\f -> if n==0 then 1 else n*f (n-1))
fix
?
fix = \f -> (\x->f (x x)) (\x->f (x x))
> fac = fix (\f->\n->if (n==0) 1 (f (pred n)))
> fac 5
120
We can add some syntactic sugar to make our language nicer
Multiple arguments: | \x y -> e | ⟹ | \x -> \y -> e
|
---|---|---|---|
Function definitions: | f x y z = e | ⟹ | f = \ x y z -> e
|
Local definitions: | let x = e1 in e2 | ⟹ | (\x->e2) e1
|
Expr
eval
readEvalPrintLoop