-
Notifications
You must be signed in to change notification settings - Fork 1
/
intro1.hs
74 lines (62 loc) · 1.97 KB
/
intro1.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
-- http://okmij.org/ftp/tagless-final/course/Intro1.hs
-- * Tagless Typed Interpreters, introduction
module Intro1 where
-- We would like to embed an (object) language whose expressions
-- look like
-- -(1 + 2)
-- * 8 + (- (1+2))
-- The expressions are built of integer literals, negation and addition.
-- The latter is one of our running example, please take note.
-- * Deep/initial embedding
-- The data type of expressions
data Exp
= Lit Int
| Neg Exp
| Add Exp Exp
-- A sample expression: our first running example
ti1 = Add (Lit 8) (Neg (Add (Lit 1) (Lit 2)))
-- * //
-- The evaluator
-- It proceeds by case analysis on the expression
eval :: Exp -> Int
eval (Lit n) = n
eval (Neg e) = -eval e
eval (Add e1 e2) = eval e1 + eval e2
ti1_eval = eval ti1
-- 5
-- * //
-- A different way to write the evaluator:
-- using the `constructor functions'
type Repr = Int
lit :: Int -> Repr
lit n = n
neg :: Repr -> Repr
neg e = -e
-- What is the inferred type for add? What type should we rather assign?
add e1 e2 = e1 + e2
-- Perhaps this already reminds someone of the denotational semantics.
-- More reminders to come.
-- Our sample expression in the final form:
-- I just downcased ti1
tf1 = add (lit 8) (neg (add (lit 1) (lit 2)))
-- 5
-- * Shallow (metacircular) embedding (to be called final)
-- * //
-- But the datatype way (initial way) lets us `evaluate' ti1
-- in a different way: to pretty-print it
view :: Exp -> String
view (Lit n) = show n
view (Neg e) = "(-" ++ view e ++ ")"
view (Add e1 e2) = "(" ++ view e1 ++ " + " ++ view e2 ++ ")"
ti1_view = view ti1
-- "(8 + (-(1 + 2)))"
-- How can we evaluate tf1 differently? It seems that the evaluator
-- is hard-wired into tf1...
-- Indeed, the constructor functions lit, neg, and add all have
-- return type that is set to Int. The evaluator `view' returns a string.
-- So, at the very least we must find a way to parameterize the constructor
-- functions by the result type.
main = do
print ti1_eval
print tf1
print ti1_view