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
|
module PostUnfold (unAlias, postUnfold, removeCopies) where
import AnsiCodes (yellow)
import Function (first, second)
import List (delete, find, partition)
import Pretty (Doc, (<+>), ($$), pPrint, text)
import Utils (count, countBy)
import FlatCurry.Types
import FlatCurryGoodies ( addPartCallArg, funcsInExps, isFuncCall, isPartCall
, isVar, maximumVarIndex, mkLet, trExpr
, prelApply, prelFailed, prelPEVAL )
import FlatCurryPretty (ppExp, indent)
import NameChange (NameChange, ncRenaming, ncResultants, ncExpr)
import Normalization ( simplifyExpr, normalizeFreeExpr
, freshResultant, renameResultant)
import Output (colorWith, traceDetail)
import PevalBase (Renaming, Resultant, ppResultant, mkFuncCall)
import PevalOpts (Options)
postUnfold :: Options -> [QName] -> Renaming -> [Resultant]
-> (Renaming, [Resultant])
postUnfold opts fs rho0 rs0 = go rho0 rs0
where
go rho rs | rs' == rs = (rho, rs)
| otherwise = go rho' rs'
where (rho', rs') = unAlias rho (puResultants opts fs rs)
unAlias :: Renaming -> [Resultant] -> (Renaming, [Resultant])
unAlias rho rs = remove duplicates $ remove aliases (rho, rs)
removeCopies :: Prog -> Renaming -> [Resultant] -> (Renaming, [Resultant])
removeCopies (Prog _ _ _ fs _) rho rs = remove (copies fs rho) (rho, rs)
aliases :: [Resultant] -> (NameChange, [Resultant])
aliases = foldr checkAlias ([], [])
where
checkAlias r@((f, vs), e) (as, rs) = case e of
Comb FuncCall g es | f /= g && es == map Var vs
-> ((f, g) : as, rs)
_ -> ( as, r : rs)
duplicates :: [Resultant] -> (NameChange, [Resultant])
duplicates [] = ([], [])
duplicates (r@((f, vs), e) : rs) = case break isDuplicate rs of
(_ , [] ) -> second (r:) (duplicates rs)
(rs1, ((g, _), _):rs2) -> let (als, rs') = duplicates (rs1 ++ rs2)
in ((g, f) : als, r : rs')
where isDuplicate ((g, vs'), e') = vs == vs' && ncExpr [(f, g)] e == e'
copies :: [FuncDecl] -> Renaming -> [Resultant] -> (NameChange, [Resultant])
copies _ _ [] = ([], [])
copies fs rho (r@((f, vs), e) : rs) = case find isCopy fs of
Nothing -> second (r:) (copies fs rho rs)
Just (Func g _ _ _ _) -> first ((f, g) :) (copies fs rho rs)
where
isCopy (Func g _ _ _ rule) = case rule of
Rule vs' e' -> vs == vs' && ncExpr [(f, g)] e == e'
&& (mkFuncCall (g, map negate vs), (f, map negate vs))
`elem` rho
_ -> False
remove :: ([Resultant] -> (NameChange, [Resultant]))
-> (Renaming, [Resultant]) -> (Renaming, [Resultant])
remove identify (rho, rs) = (ncRenaming nc rho, ncResultants nc rs')
where
(as, rs') = identify rs
nc = map (\(f, g) -> (f, deepLookup g as)) as
deepLookup x xys = case lookup x xys of
Nothing -> x
Just y -> deepLookup y xys
puResultants :: Options -> [QName] -> [Resultant] -> [Resultant]
puResultants opts fs rs = removeRedundantRules fs
$ map (puResultant (initEnv opts rs)) rs
removeRedundantRules :: [QName] -> [Resultant] -> [Resultant]
removeRedundantRules fs rs = filter (not . redundant) rs
where redundant r@((f, _), _) = f `notElem` fs && countFuncCalls f
(map snd (delete r rs)) == 0
data PUEnv = PUEnv
{ peOptions :: Options
, peResultants :: [Resultant]
}
initEnv :: Options -> [Resultant] -> PUEnv
initEnv opts rs = PUEnv opts rs
puResultant :: PUEnv -> Resultant -> Resultant
puResultant env = renameResultant . second (puExpr env)
puTrace :: PUEnv -> Doc -> a -> a
puTrace PUEnv { peOptions = o } doc x = traceDetail o (colorWith o yellow str) x
where str = pPrint (text "Compression:" <+> doc) ++ "\n"
puExpr :: PUEnv -> Expr -> Expr
puExpr env = normalizeFreeExpr
. simplifyExpr
. trExpr Var Lit (puComb env) Free Or Case Branch Let Typed
puComb :: PUEnv -> CombType -> QName -> [Expr] -> Expr
puComb env ct qn es = case ct of
FuncCall | qn == prelApply -> puApply es
| qn == prelPEVAL -> Comb ct qn es
| otherwise -> puFuncCall env qn es
_ -> Comb ct qn es
puApply :: [Expr] -> Expr
puApply exs = case exs of
[Comb ct f es, e2] | isPartCall ct -> addPartCallArg ct f es e2
[_, _] -> Comb FuncCall prelApply exs
_ -> error "PostUnfold.puApply"
puFuncCall :: PUEnv -> QName -> [Expr] -> Expr
puFuncCall env f es = case find ((== f) . resultantName) (peResultants env) of
Just r | isSimple r || isAlias r || isIntermediate env r
-> unfold env r es
_ -> Comb FuncCall f es
resultantName :: Resultant -> QName
resultantName ((f, _), _) = f
isSimple :: Resultant -> Bool
isSimple ((_, _), e) = countFuncs [e] == 0
isAlias :: Resultant -> Bool
isAlias ((_, _), e) = case e of
Comb FuncCall _ es -> all isVar es
_ -> False
isIntermediate :: PUEnv -> Resultant -> Bool
isIntermediate env ((f, _), e)
= countFuncCalls f [e] == 0
&& countFuncCalls f (map snd (peResultants env)) == 1
unfold :: PUEnv -> Resultant -> [Expr] -> Expr
unfold opts r es = puTrace opts doc e''
where
r'@((f, vs'), e') = freshResultant (maximumVarIndex es + 1) r
e'' = mkLet (zip vs' es) e'
doc = indent (text "Unfolding call" $$ ppExp (Comb FuncCall f es))
$$ indent (text "with definition" $$ ppResultant r')
$$ indent (text "to expression" $$ ppExp e'')
countFuncs :: [Expr] -> Int
countFuncs = countBy (`notElem` [prelFailed]) . funcsInExps
countFuncCalls :: QName -> [Expr] -> Int
countFuncCalls f = count f . funcsInExps
|