-
Notifications
You must be signed in to change notification settings - Fork 4
/
TTIF.hs
307 lines (227 loc) · 7.59 KB
/
TTIF.hs
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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
{-# LANGUAGE GADTs #-}
{-# LANGUAGE NoMonomorphismRestriction #-}
-- * Relating initial and final representations
module TTIF where
import TTF as F hiding (main) -- The final embedding
-- * Initial embedding of our language, in HOAS
-- * (superset of the running example in Xi, Chen and Chen (POPL2003))
-- In the latter paper, the tagless interpretation of the
-- language was the motivation for GADT.
-- The initial embedding is not-extensible.
-- The Var operation is used only during evaluation.
-- Var corresponds to a CSP value in MetaOCaml or
-- HOASLift in Xi, Chen and Chen (POPL2003)
-- The parameter h is the `hypothetical environment':
-- h t is the type of an environment `cell' holding a value of the type t.
data IR h t where
INT :: Int -> IR h Int
BOOL :: Bool -> IR h Bool
Add :: IR h Int -> IR h Int -> IR h Int
Mul :: IR h Int -> IR h Int -> IR h Int
Leq :: IR h Int -> IR h Int -> IR h Bool
IF :: IR h Bool -> IR h t -> IR h t -> IR h t
Var :: h t -> IR h t
Lam :: (IR h t1 -> IR h t2) -> IR h (t1->t2)
App :: IR h (t1->t2) -> IR h t1 -> IR h t2
Fix :: (IR h t -> IR h t) -> IR h t
-- * Sample terms and their inferred types
-- Compared to the terms in the final embedding, the initial
-- embedding terms below look capitalized (which is what I did in Emacs)
ti1 = Add (INT 1) (INT 2)
-- ti1 :: IR h Int
-- * th1 :: (Symantics repr) => repr Int
ti2 = Lam (\x -> Add x x)
-- ti2 :: IR h (Int -> Int)
-- th2 :: (Symantics repr) => repr (Int -> Int)
ti3 = Lam (\x -> Add (App x (INT 1)) (INT 2))
-- ti3 :: IR h ((Int -> Int) -> Int)
-- th3 :: (Symantics repr) => repr ((Int -> Int) -> Int)
tipow = Lam (\x -> Fix (\self -> Lam (\n ->
IF (Leq n (INT 0)) (INT 1)
(Mul x (App self (Add n (INT (-1))))))))
-- tipow :: IR h (Int -> Int -> Int)
-- * tpow :: (Symantics repr, BoolSYM repr, MulSYM repr, FixSYM repr) =>
-- * repr (Int -> Int -> Int)
tipow7 = Lam (\x -> App (App tipow x) (INT 7))
tipow72 = App tipow7 (INT 2)
-- tipow72 :: IR h Int
-- tpow72 :: (Symantics repr, BoolSYM repr, MulSYM repr, FixSYM repr) =>
-- repr Int
-- * //
-- * Initial evaluator
-- It is total (modulo potential non-termination in fix)
-- No exceptions are to be raised, and no pattern-match failure
-- may occur. All pattern-matching is _syntactically_, patently complete.
-- We use the same R as in TTF.hs
evalI :: IR R t -> t
evalI (INT n) = n
evalI (BOOL n) = n
evalI (Add e1 e2) = evalI e1 + evalI e2
evalI (Mul e1 e2) = evalI e1 * evalI e2
evalI (Leq e1 e2) = evalI e1 <= evalI e2
evalI (IF be et ee) = if (evalI be) then evalI et else evalI ee
evalI (Var v) = unR v
evalI (Lam b) = \x -> evalI (b . Var . R $ x)
evalI (App e1 e2) = (evalI e1) (evalI e2)
evalI (Fix f) = evalI (f (Fix f))
ti1_eval = evalI ti1
-- 3
ti2_eval = evalI ti2
-- ti2_eval :: Int -> Int
-- ti2_eval is a function, can't be shown, but can be applied
ti2_eval' = ti2_eval 21
-- 42
ti3_eval = evalI ti3
-- ti3_eval :: (Int -> Int) -> Int
tipow72_eval = evalI tipow72
-- 128
-- * //
-- * Initial viewer (another evaluator)
-- The code essentially the same as the final one:
-- unS is replaced by viewI'
viewI' :: IR S t -> VarCounter -> String
viewI' (INT x) = const $ show x
viewI' (BOOL x) = const $ show x
viewI' (Add e1 e2) = \h ->
"(" ++ viewI' e1 h ++ "+" ++ viewI' e2 h ++ ")"
viewI' (Mul e1 e2) = \h ->
"(" ++ viewI' e1 h ++ "*" ++ viewI' e2 h ++ ")"
viewI' (Leq e1 e2) = \h ->
"(" ++ viewI' e1 h ++ "<=" ++ viewI' e2 h ++ ")"
viewI' (IF be et ee) = \h ->
unwords["(if", viewI' be h, "then", viewI' et h,
"else", viewI' ee h,")"]
viewI' (Var x) = unS x
viewI' (Lam e) = \h ->
let x = "x" ++ show h
in "(\\" ++ x ++ " -> " ++
viewI' (e (Var . S $ const x)) (succ h) ++ ")"
viewI' (App e1 e2) = \h ->
"(" ++ viewI' e1 h ++ " " ++ viewI' e2 h ++ ")"
viewI' (Fix e) = \h ->
let self = "self" ++ show h
in "(fix " ++ self ++ "." ++
viewI' (e (Var . S $ const self)) (succ h) ++ ")"
viewI e = viewI' e 0
ti1_view = viewI ti1
-- "(1+2)"
ti2_view = viewI ti2
-- "(\\x0 -> (x0+x0))"
ti3_view = viewI ti3
-- "(\\x0 -> ((x0 1)+2))"
tipow_view = viewI tipow
-- "(\\x0 -> (fix self1.(\\x2 ->
-- (if (x2<=0) then 1 else (x0*(self1 (x2+-1))) ))))"
-- * This is all very similar to the final approach
-- * The same guarantees
-- No pattern-matching failure, only closed terms can be evaluated
-- The reason is that GADT IR encodes all and only well-typed terms
-- of the object language.
-- * IR is not extensible though
-- Because both initial and final embedding encode all and only
-- well-typed object terms, one may wonder if the two embeddings
-- may be related.
-- * //
-- * Relating Initial and Final Tagless representations
instance Symantics (IR h) where
int = INT
add = Add
lam = Lam
app = App
instance MulSYM (IR h) where
mul = Mul
instance BoolSYM (IR h) where
bool = BOOL
leq = Leq
if_ = IF
instance FixSYM (IR h) where
fix = Fix
-- * Looks like the identity, doesn't it?
-- * //
-- * From Final to Initial
f2i :: IR h t -> IR h t
f2i = id
-- It does look like the identity
-- Conversion of sample terms
ti2' = f2i F.th2
-- Now we can evaluate it using different initial interpreters
ti2'_eval = evalI ti2'
-- ti2'_eval :: Int -> Int
ti2'_eval' = ti2'_eval 21
-- 42
ti2'_view = viewI ti2'
--"(\\x0 -> (x0+x0))"
-- The same for the power example
tipow72' = f2i F.tpow72
tipow72'_eval = evalI tipow72'
-- 128
tipow72'_view = viewI tipow72'
-- "((\\x0 -> (((\\x1 ->
-- (fix self2.(\\x3 -> (if (x3<=0) then 1 else (x1*(self2 (x3+-1))) ))))
-- x0) 7)) 2)"
-- * //
-- * From Initial to Final
i2f :: (Symantics repr, BoolSYM repr, MulSYM repr, FixSYM repr) =>
IR repr t -> repr t
i2f (INT x) = int x
i2f (BOOL x) = bool x
i2f (Add e1 e2) = add (i2f e1) (i2f e2)
i2f (Mul e1 e2) = mul (i2f e1) (i2f e2)
i2f (Leq e1 e2) = leq (i2f e1) (i2f e2)
i2f (IF be et ee) = if_ (i2f be) (i2f et) (i2f ee)
i2f (Var v) = v -- polymorphic lift
i2f (Lam e) = lam(\x -> i2f (e (Var x)))
i2f (App e1 e2) = app (i2f e1) (i2f e2)
i2f (Fix e) = fix(\x -> i2f (e (Var x)))
-- Convert sample terms
tf2' = i2f ti2
-- tf2' :: (Symantics repr, BoolSYM repr, MulSYM repr, FixSYM repr) =>
-- repr (Int -> Int)
-- Now we can evaluate it using different final interpreters
tf2'_eval = F.eval tf2'
-- tf2'_eval :: Int -> Int
tf2'_eval' = tf2'_eval 21
-- 42
tf2'_view = F.view tf2'
-- "(\\x0 -> (x0+x0))"
-- The same for the power term
tfpow72' = i2f tipow72
tfpow72'_eval = F.eval tfpow72'
-- 128
tfpow72'_view = F.view tfpow72'
-- the same as tipow72'_view
-- * //
-- * Verifying Initial -> Final -> Initial
-- * ifi :: IR (IR h) t -> IR h t
ifi ir = f2i . i2f $ ir
tipow72'_eval'' = evalI . ifi $ tipow72
-- 128
tipow72'_view'' = viewI . ifi $ tipow72
-- * Verifying Final -> Initial -> Final
fif fr = i2f . f2i $ fr
-- fif :: (Symantics repr, BoolSYM repr, MulSYM repr, FixSYM repr) =>
-- IR repr t -> repr t
tfpow72'_eval'' = F.eval . fif $ F.tpow72
-- 128
tfpow72'_view'' = F.view . fif $ F.tpow72
-- * Relation between initial and final is a bijection
main = do
print ti1_eval
print ti2_eval'
print tipow72_eval
print ti1_view
print ti2_view
print ti3_view
print tipow_view
print ti2'_eval'
print tipow72'_eval
print ti2'_view
print tipow72'_view
print tf2'_eval'
print tfpow72'_eval
print tf2'_view
print tfpow72'_view
print tipow72'_eval''
print tipow72'_view''
print tfpow72'_eval''
print tfpow72'_view''