summaryrefslogtreecommitdiff
blob: f32e9d6cfed4875064e5f5407e21e7eee707e5b8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
> {-# OPTIONS -fglasgow-exts #-}

Parameterized Syntax
~~~~~~~~~~~~~~~~~~~~

> type Name       = String
> 
> data Expr e d   = Let d e
>                 | App e e
>                 | Var Name
>                 | Int Int
> 
> data Decl e d   = Fun Name [Name] e


Parameterized Semantics 
~~~~~~~~~~~~~~~~~~~~~~~

> data Val        = IntVal Int | FunVal (Val -> Val)
> type Env        = [(Name,Val)]
> 
> class Eval e d | e -> d, d -> e where 
>   expr :: e -> Env -> Val
>   decl :: d -> Env -> Env 
> 
> instance (Eval e d) => Eval (Expr e d) (Decl e d) where
>   expr e env = case e of
>     Let d e   -> expr e (decl d env ++ env)
>     App e1 e2 -> case expr e1 env of
>                    FunVal f -> f (expr e2 env)
>                    _ -> error "Type error."
>     Var x     -> case lookup x env of
>                    Just v  -> v
>                    Nothing -> error "Undefined variable."
>     Int x     -> IntVal x
> 
>   decl d env = case d of
>     Fun f xs e -> [(f,args env xs)]
>       where args env (x:xs) = FunVal (\v -> args ((x,v):env) xs)
>             args env []     = expr e env


Language 1: Tying the Knot 
~~~~~~~~~~~~~~~~~~~~~~~~~~

> newtype Expr1 = E1 (Expr Expr1 Decl1)
> newtype Decl1 = D1 (Decl Expr1 Decl1)
> 
> instance Eval Expr1 Decl1 where 
>   expr (E1 e) env = expr e env
>   decl (D1 e) env = decl e env
 
Examples:

> var1 x      = E1 $ Var x
> int1 x      = E1 $ Int x
> app1 f x    = E1 $ App f x
> let1 d e    = E1 $ Let d e
> fun1 f xs e = D1 $ Fun f xs e
>  
> test1 e = expr
>         ( let1 (fun1 "id" ["x"]        $ var1 "x") 
>         $ let1 (fun1 "const" ["x","y"] $ var1 "x") e) []
> 
> ex1     = test1 $ var1 "id"    `app1` int1 2
> ex2     = test1 $ var1 "const" `app1` int1 2    `app1` int1 3
> ex3     = test1 $ var1 "const" `app1` var1 "id" `app1` int1 2 `app1` int1 3


Language 2: Tying the Know with an Extension
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

> data Expr2    = E2 (Expr Expr2 Decl2)
>               | Add Expr2 Expr2
> newtype Decl2 = D2 (Decl Expr2 Decl2)
> 
> instance Eval Expr2 Decl2 where
>   expr (E2 e) env     = expr e env
>   expr (Add e1 e2) env = case (expr e1 env, expr e2 env) of
>                            (IntVal x, IntVal y) -> IntVal (x+y)
>                            _ -> error "Type error."
>   decl (D2 d) env = decl d env
 
Examples:

> var2 x      = E2 $ Var x
> int2 x      = E2 $ Int x
> app2 f x    = E2 $ App f x
> let2 d e    = E2 $ Let d e
> fun2 f xs e = D2 $ Fun f xs e
> 
> test2 e = expr
>         ( let2 (fun2 "id" ["x"]        $ var2 "x") 
>         $ let2 (fun2 "const" ["x","y"] $ var2 "x") e) []
> 
> ex4     = test2 $ var2 "id"    `app2` int2 2
> ex5     = test2 $ var2 "const" `app2` int2 2    `app2` int2 3
> ex6     = test2 $ var2 "const" `app2` var2 "id" `app2` int2 2 `app2` int2 3
> ex7     = test2 $ var2 "id" `app2` (int2 3 `Add` int2 7)


> instance Show Val where
>   show val = case val of
>     IntVal x -> show x
>     FunVal _ -> error "<function>"