-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathHhiReducer.hs
More file actions
178 lines (147 loc) · 6.62 KB
/
HhiReducer.hs
File metadata and controls
178 lines (147 loc) · 6.62 KB
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
module HhiReducer where
import Parser ( Expr(..) )
import Control.Monad.Fix (fix)
import CLTerm
import Data.Maybe (fromJust)
-- | a compiled expression
data CExpr =
CComb Combinator
| CApp CExpr CExpr
| CFun (CExpr -> CExpr)
| CInt Integer
instance Show CExpr where
show (CComb k) = show k
show (CApp a b) = "(" ++ show a ++ " " ++ show b ++ ")"
show (CFun _f) = "<function>"
show (CInt i) = show i
-- | Convert CL expression to CExpr
clToCExpr :: CL -> CExpr
clToCExpr (Com c) = CComb c
clToCExpr (INT i) = CInt i
clToCExpr (cl1 :@ cl2) = CApp (clToCExpr cl1) (clToCExpr cl2)
-- | Helper functions for Scott-encoded booleans
trueCExpr :: CExpr
trueCExpr = link primitives (translate trueCL)
falseCExpr :: CExpr
falseCExpr = link primitives (translate falseCL)
-- | translating a CL term expression into a compiled expression
translate :: CL -> CExpr
translate (fun :@ arg) = CApp (translate fun) (translate arg)
translate (INT k) = CInt k
translate (Com c) = CComb c
-- | apply a CExpr of shape (CFun f) to argument x by evaluating (f x)
infixl 0 !
(!) :: CExpr -> CExpr -> CExpr
(CFun f) ! x = f x
(CComb c) ! x = link primitives (CComb c) ! x
x ! y = error $ "can't handle " ++ show x
{-# INLINE (!) #-}
-- | "link" a compiled expression into Haskell native functions.
-- application terms will be transformed into real (!) applications
-- combinator symbols will be replaced by their actual function definition
link :: CombinatorDefinitions -> CExpr -> CExpr
link definitions (CApp fun arg) = link definitions fun ! link definitions arg
link definitions (CComb comb) = case lookup comb definitions of
Nothing -> resolveBulk comb
Just e -> e
link _definitions expr = expr
linkLog :: CombinatorDefinitions -> CExpr -> CExpr
linkLog definitions (CApp fun arg) = link definitions fun ! link definitions arg
linkLog definitions (CComb comb) = case lookup comb definitions of
Nothing -> resolveBulk comb
Just e -> e
linkLog _definitions expr = expr
-- | translate and link in one go
transLink :: CombinatorDefinitions -> CL -> CExpr
transLink definitions (fun :@ arg) = transLink definitions fun ! transLink definitions arg
transLink _definitions (INT k) = CInt k
transLink definitions (Com comb) = case lookup comb definitions of
Nothing -> resolveBulk comb
Just e -> e
transLinkLog :: CombinatorDefinitions -> CL -> CExpr
transLinkLog definitions (fun :@ arg) = transLink definitions fun ! transLink definitions arg
transLinkLog _definitions (INT k) = CInt k
transLinkLog definitions (Com comb) = case lookup comb definitions of
Nothing -> resolveBulkLog comb
Just e -> e
type CombinatorDefinitions = [(Combinator,CExpr)]
-- | the set of primary operations: combinators + basic arithmetic functions
primitives :: CombinatorDefinitions
primitives = let (-->) = (,) in
[ I --> CFun id
, K --> CFun (CFun . const)
, S --> comS --CFun (\f -> CFun $ \g -> CFun $ \x -> f!x!(g!x)) -- S F G X = F X (G X)
, B --> comB --CFun (\f -> CFun $ \g -> CFun $ \x -> f!(g!x)) -- B F G X = F (G X)
, C --> comC --CFun (\f -> CFun $ \g -> CFun $ \x -> f!x!g) -- C F G X = F X G
, A --> CFun (\x -> CFun $ \y -> y) -- A X Y = Y
, R --> CFun (\f -> CFun $ \g -> CFun $ \x -> g!x!f) -- R F G X = G X F
, T --> CFun (CFun . const) -- T X Y = X
, B' --> comB' --CFun (\p -> CFun $ \q -> CFun $ \r -> CFun $ \s -> p!q!(r!s)) -- B' P Q R S = P Q (R S)
, C' --> comC' --CFun (\p -> CFun $ \q -> CFun $ \r -> CFun $ \s -> p!(q!s)!r) -- C' P Q R S = P (Q S) R
, S' --> comS' --CFun (\p -> CFun $ \q -> CFun $ \r -> CFun $ \s -> p!(q!s)!(r!s)) -- S' P Q R S = P (Q S) (R S)
, Y --> CFun (\(CFun f) -> fix f)
, ADD --> arith (+)
, SUB --> arith (-)
, SUB1 --> CFun sub1
, MUL --> arith (*)
, EQL --> compArith (==)
, GEQ --> compArith (>=)
, LEQ --> compArith (<=)
, ZEROP --> CFun isZero
]
resolveBulkLog :: Combinator -> CExpr
resolveBulkLog (BulkCom c n) = breakBulkLog (fromString c) n
where
breakBulkLog :: Combinator -> Int -> CExpr
breakBulkLog c 1 = com c
breakBulkLog B n = foldr ((!) . (bs!!)) comB (init $ bits n) where
bs = [sbi, comB ! (comB ! comB) ! sbi]
breakBulkLog c n = foldr ((!) . (bs!!)) (prime c) (init $ bits n) ! comI where
bs = [sbi, comB ! (comB ! prime c) ! sbi]
prime c = comB ! (comB ! com c) ! comB
com :: Combinator -> CExpr
com c = fromJust $ lookup c primitives
sbi :: CExpr
sbi = comS ! comB ! comI
bits :: Integral t => t -> [t]
bits n = r:if q == 0 then [] else bits q where (q, r) = divMod n 2
resolveBulk :: Combinator -> CExpr
resolveBulk (BulkCom "B" n) = iterate (comB' !) comB !! (n-1)
resolveBulk (BulkCom "C" n) = iterate (comC' !) comC !! (n-1)
resolveBulk (BulkCom "S" n) = iterate (comS' !) comS !! (n-1)
resolveBulk anyOther = error $ "not a known combinator: " ++ show anyOther
comI :: CExpr
comI = CFun id
comS :: CExpr
comS = CFun (\f -> CFun $ \g -> CFun $ \x -> f!x!(g!x)) -- S F G X = F X (G X)
comS' :: CExpr
comS' = CFun (\p -> CFun $ \q -> CFun $ \r -> CFun $ \s -> p!(q!s)!(r!s)) -- S' P Q R S = P (Q S) (R S)
comB :: CExpr
comB = CFun (\f -> CFun $ \g -> CFun $ \x -> f!(g!x)) -- B F G X = F (G X)
comB' :: CExpr
comB' = CFun (\p -> CFun $ \q -> CFun $ \r -> CFun $ \s -> p!q!(r!s)) -- B' P Q R S = P Q (R S)
comC :: CExpr
comC = CFun (\f -> CFun $ \g -> CFun $ \x -> f!x!g) -- C F G X = F X G
comC' :: CExpr
comC' = CFun (\p -> CFun $ \q -> CFun $ \r -> CFun $ \s -> p!(q!s)!r) -- C' P Q R S = P (Q S) R
arith :: (Integer -> Integer -> Integer) -> CExpr
arith op = CFun $ \(CInt a) -> CFun $ \(CInt b) -> CInt (op a b)
-- Comparison operations that return TRUE/FALSE combinators
compArith :: (Integer -> Integer -> Bool) -> CExpr
compArith op = CFun $ \(CInt a) -> CFun $ \(CInt b) -> if op a b then trueCExpr else falseCExpr
eql :: (Eq a) => a -> a -> CExpr
eql n m = if n == m then trueCExpr else falseCExpr
geq :: (Ord a) => a -> a -> CExpr
geq n m = if n >= m then trueCExpr else falseCExpr
leq :: (Ord a) => a -> a -> CExpr
leq n m = if n <= m then trueCExpr else falseCExpr
gre :: (Ord a) => a -> a -> CExpr
gre n m = if n > m then trueCExpr else falseCExpr
le :: (Ord a) => a -> a -> CExpr
le n m = if n < m then trueCExpr else falseCExpr
sub1 :: CExpr -> CExpr
sub1 (CInt n) = CInt $ n -1
sub1 x = error $ show x ++ " is not a number"
isZero :: CExpr -> CExpr
isZero (CInt n) = if n == 0 then trueCExpr else falseCExpr
isZero _ = falseCExpr