--
import List(find)
-----------------------------------------------
-- A simple functional language
type Var = String
data Term0 =
Add0 Term0 Term0
| Const0 Int
| Lambda0 Var Term0
| App0 Term0 Term0
| Var0 Var
data Value0 =
Int0 Int
| Fun0 Var Term0 Env0
data Env0 = E0 [(Var,Value0)]
------------------------------------------------
-- A simple evaluator
eval0 :: Env0 -> Term0 -> Value0
eval0 (e @ (E0 xs)) t =
case t of
Add0 x y -> plus (eval0 e x) (eval0 e y)
Const0 n -> Int0 n
Var0 s -> look xs s
Lambda0 s t -> Fun0 s t e
App0 f x -> apply (eval0 e f) (eval0 e x)
where plus (Int0 x) (Int0 y) = Int0 (x+y)
look ((x,v):xs) s = if s==x then v else look xs s
apply (Fun0 v t e) x = eval0 (extend e v x) t
extend (E0 xs) v x = (E0((v,x):xs))
-------------------------------------------------------------
-- Now let's try and make the environment abstract
data Term1 =
Add1 Term1 Term1
| Const1 Int
| Lambda1 Var Term1
| App1 Term1 Term1
| Var1 Var
data Value1 e =
Int1 Int
| Fun1 Var Term1 e
------------------------------------------------
-- A simple evaluator abstract on the environment type
eval1 :: e -> (e -> Var -> Value1 e) -> (e -> Var -> Value1 e -> e) ->
Term1 -> Value1 e
eval1 e look extend t =
case t of
Add1 x y -> plus (eval e x) (eval e y)
Const1 n -> Int1 n
Var1 s -> look e s
Lambda1 s t -> Fun1 s t e
App1 f x -> apply (eval e f) (eval e x)
where plus (Int1 x) (Int1 y) = Int1 (x+y)
apply (Fun1 v t e) x = eval (extend e v x) t
eval e x = eval1 e look extend x
--------------------------------------------------------
-- Now supose we want to add pairs, or some other new type
data Term2 =
Add2 Term2 Term2
| Const2 Int
| Lambda2 Var Term2
| App2 Term2 Term2
| Var2 Var
| Pair2 Term2 Term2 -- (3, 4+5)
| Let2 Pat Term2 Term2 -- let (x,y) = f x in x+y
data Value2 e =
Int2 Int
| Fun2 Var Term2 e
| Prod2 (Value2 e) (Value2 e)
data Pat = Pat Var Var
-----------------------------------------------------------
-- Now inorder to maintain the abstraction of enviroments
-- the number of operators passed as parameters is getting
-- out of hand
eval2 :: e -> (e -> Var -> Value2 e) ->
(e -> Var -> Value2 e -> e) ->
(e -> Pat -> Value2 e -> e) ->
Term2 -> Value2 e
eval2 e look extend extpat t =
case t of
Add2 x y -> plus (eval e x) (eval e y)
Const2 n -> Int2 n
Var2 s -> look e s
Lambda2 s t -> Fun2 s t e
App2 f x -> apply (eval e f) (eval e x)
Pair2 x y -> Prod2 (eval e x) (eval e y)
Let2 p x y -> eval (extpat e p (eval e x)) y
where plus (Int2 x) (Int2 y) = Int2 (x+y)
apply (Fun2 v t e) x = eval (extend e v x) t
eval e x = eval2 e look extend extpat x
-----------------------------------------------------------
-- Lets capture the set of operators on the abstract environments
-- as a type class
class Environment e where
look :: e -> Var -> Value2 e
extend:: e -> Var -> Value2 e -> e
extpat :: e -> Pat -> Value2 e -> e
eval3 :: Environment e => e -> Term2 -> Value2 e
eval3 e t =
case t of
Add2 x y -> plus (eval3 e x) (eval3 e y)
Const2 n -> Int2 n
Var2 s -> look e s
Lambda2 s t -> Fun2 s t e
App2 f x -> apply (eval3 e f) (eval3 e x)
Pair2 x y -> Prod2 (eval3 e x) (eval3 e y)
Let2 p x y -> eval3 (extpat e p (eval3 e x)) y
where plus (Int2 x) (Int2 y) = Int2 (x+y)
apply (Fun2 v t e) x = eval3 (extend e v x) t
-------------------------------------------------------------
-- Lets try instantiating the Environment type class at
-- several different types
data Env3 = E3 [(Var,Value2 Env3)]
instance Environment Env3 where
look (E3((x,y):xs)) v = if x==v then y else look (E3 xs) v
extend (E3 xs) v x = E3 ((v,x):xs)
extpat (E3 xs) (Pat x y) (Prod2 a b) = E3 ((x,a):(y,b):xs)
data Env4 = E4 (Var -> Value2 Env4)
instance Environment Env4 where
look (E4 f) v = f v
extend (E4 f) v x = E4(\ y -> if y==v then x else f y)
extpat (E4 f) (Pat x y) (Prod2 a b) =
E4(\ z -> if x==z then a else if y==z then b else f z)
--------------------------------------------------------------
-- let (f,g) = (\ x -> x+1, \ y -> y + 3)
-- in f (g 5)
prog =
Let2 (Pat "f" "g")
(Pair2 (Lambda2 "x" (Add2 (Var2 "x") (Const2 1)))
(Lambda2 "y" (Add2 (Var2 "y") (Const2 3))))
(App2 (Var2 "f") (App2 (Var2 "g") (Const2 5)))
ans = eval3 (E3 []) prog
ans2 = eval3 (E4 (\ x -> error "no such name")) prog
--------------------------------------------------------
data EnvironmentC e =
EnvC {lookM :: e -> Var -> Value2 e,
extendM :: e -> Var -> Value2 e -> e,
extpatM :: e -> Pat -> Value2 e -> e
}
eval4 :: EnvironmentC a -> a -> Term2 -> Value2 a
eval4 d e t =
case t of
Add2 x y -> plus (eval4 d e x) (eval4 d e y)
Const2 n -> Int2 n
Var2 s -> lookM d e s
Lambda2 s t -> Fun2 s t e
App2 f x -> apply (eval4 d e f) (eval4 d e x)
Pair2 x y -> Prod2 (eval4 d e x) (eval4 d e y)
Let2 p x y -> eval4 d (extpatM d e p (eval4 d e x)) y
where plus (Int2 x) (Int2 y) = Int2 (x+y)
apply (Fun2 v t e) x = eval4 d (extendM d e v x) t
-----------------------------------------------------
e3Dict = EnvC
{ lookM = \ (E3((x,y):xs)) v ->
if x==v then y else lookM e3Dict (E3 xs) v
, extendM = \ (E3 xs) v x -> E3((v,x):xs)
, extpatM = \ (E3 xs) (Pat x y) (Prod2 a b) ->
E3((x,a):(y,b):xs)
}
e4Dict = EnvC
{ lookM = \ (E4 f) v -> f v
, extendM = \ (E4 f) v x ->
E4(\ y -> if y==v then x else f y)
, extpatM = \ (E4 f) (Pat x y) (Prod2 a b) ->
E4(\ z -> if x==z
then a
else if y==z
then b
else f z)
}
ans3 = eval4 e3Dict (E3 []) prog
ans4 = eval4 e4Dict (E4 (\ x -> error "no such name")) prog
--