-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathRec.hs
96 lines (76 loc) · 2.1 KB
/
Rec.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
{-| Demo on how to evaluate recursive functions via
eval/apply style interpretation.
-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE OverloadedStrings #-}
module Rec where
import Data.String (IsString(..))
type Name = String
data Expr
= Ref Name
| Bool Bool
| Int Int
| Equal Expr Expr
| Add Expr Expr
| Minus Expr Expr
| Mul Expr Expr
| Lam Name Expr
| App Expr Expr
| Rec Name Expr
| If Expr Expr Expr
deriving stock (Show)
instance IsString Expr where
fromString = Ref
instance Num Expr where
fromInteger = Int . fromInteger
(+) = Add
(-) = Minus
(*) = Mul
abs = error "abs not implemented"
signum = error "signum not implemented"
(==>) :: Name -> Expr -> Expr
x ==> b = Lam x b
(@) :: Expr -> Expr -> Expr
f @ a = App f a
(===) :: Expr -> Expr -> Expr
l === r = Equal l r
data Value
= Closure Env Name Expr
| VBool Bool
| VInt Int
deriving stock (Show)
type Env = [(Name, Value)]
l :: (Eq a) => a -> [(a, b)] -> b
l x ((y,v):ys) = if x == y then v else l x ys
eval :: Env -> Expr -> Value
eval env (Ref x) = l x env
eval env (Lam x e) = Closure env x e
eval env (App e0 e1) = case (eval env e0, eval env e1) of
(f@(Closure env' x v0), b) -> eval ((x, b) : env') v0
eval env (Rec x e) = let v = eval ((x, v) : env) e in v
eval env (Bool b) = VBool b
eval env (If p ifT ifF) = case eval env p of
VBool True -> eval env ifT
VBool False -> eval env ifF
eval env (Int i) = VInt i
eval env (Add l r) = case (eval env l, eval env r) of
(VInt l', VInt r') -> VInt (l' + r')
eval env (Mul l r) = case (eval env l, eval env r) of
(VInt l', VInt r') -> VInt (l' * r')
eval env (Minus l r) = case (eval env l, eval env r) of
(VInt l', VInt r') -> VInt (l' - r')
eval env (Equal l r) = case (eval env l, eval env r) of
(VInt l', VInt r') -> VBool (l' == r')
id_ :: Expr
id_ = "x" ==> "x"
const_ :: Expr
const_ = "x" ==> ("y" ==> "x")
ex1 :: Expr
ex1 = If (Bool False) id_ const_
ex2 :: Expr
ex2 = 2 + 3
-- sum' n = if n == 0 then 0 else n + sum' (n - 1)
sum' :: Expr
sum' = Rec "sum" $ "n" ==> If ("n" === 0) 0 ("n" + ("sum" @ ("n" - 1)))
ex3 :: Expr
ex3 = sum' @ 30