-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathPatComp.hs
225 lines (191 loc) · 7.95 KB
/
PatComp.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
module PatComp (compilePatternMatch, patBindings) where
import Data.List
import Control.Monad hiding (ap)
import Control.Monad.State hiding (ap)
import Syntax
import PPrint ()
type PatComp = State Int
compilePatternMatch :: Program -> Program
compilePatternMatch pgm = evalState (pcProgram pgm) 0
pcProgram :: Program -> PatComp Program
pcProgram = mapM pcBindGroup
pcBindGroup :: BindGroup -> PatComp BindGroup
pcBindGroup (es, iss) =
do es' <- mapM pcExpl es
iss' <- mapM (mapM pcImpl) iss
return (es', iss')
pcExpl :: Expl -> PatComp Expl
pcExpl (i, sc, alts) = do { alt <- pcAlts alts; return (i, sc, [alt]) }
pcImpl :: Impl -> PatComp Impl
pcImpl (i, alts) = do { alt <- pcAlts alts; return (i, [alt]) }
pcAlts :: [Alt] -> PatComp Alt
pcAlts [(ps, Rhs e)]
| all isPVar ps = do { e' <- pcExpr e; return (ps, Rhs e') }
where isPVar (PVar _) = True
isPVar _ = False
pcAlts qs = do us <- newVars n
rhs <- match us qs matchError
return (map PVar us, Rhs rhs)
where n = length $ fst $ head $ qs
pcRhs :: Rhs -> Expr -> PatComp Expr
pcRhs (Rhs e) _ = pcExpr e
pcRhs (Where bg rhs) def = liftM (Let bg) (pcRhs rhs def)
pcRhs (Guarded gds) def = do gds' <- mapM pcGuard gds
return $ foldr makeIf def gds'
pcGuard :: (Expr, Expr) -> PatComp (Expr, Expr)
pcGuard (e1, e2) = do e1' <- pcExpr e1
e2' <- pcExpr e2
return (e1', e2')
pcExpr :: Expr -> PatComp Expr
pcExpr (Ap e1 e2) = do e1' <- pcExpr e1
e2' <- pcExpr e2
return (Ap e1' e2')
pcExpr (Let bg e) = do bg' <- pcBindGroup bg
e' <- pcExpr e
return (Let bg' e')
pcExpr (Lambda a) = liftM Lambda (pcAlts [a])
pcExpr c@(Case e pes) =
do e' <- pcExpr e
case e' of
(Var v) -> match [v] qs matchError
e'' -> do v <- newVar
m <- match [v] qs matchError
return $ Let (bind1 v e'') m
where qs = [([p], rhs) | (p, rhs) <- pes]
pcExpr (ESign e sc) = do { e' <- pcExpr e; return $ ESign e' sc }
pcExpr c = return c
matchError :: Expr
matchError = Ap (Var "error") (Lit $ LitStr $ "Non-exhaustive patterns")
patBindings :: Expr -> Pat -> [Impl]
patBindings v (PVar i) = [(i, [([], Rhs v)])]
patBindings _ PWildcard = []
patBindings v (PAs i p) = (i, [([], Rhs v)]) : patBindings v p
patBindings v (PLit _) = []
patBindings v (PCon con pats)
= concat [patBindings (makeSel con n v) p | (p, n) <- zip pats [1..]]
makeSel :: Const -> Int -> Expr -> Expr
--makeSel con i e = ap (Var "SEL") [Lit (LitInt i), e]
makeSel con i e = expr
where vs = ["@@"++show v | v <- [1..(conArity con)]]
body = Rhs $ Var $ vs !! (i-1)
receiver = Lambda ([PVar v | v <- vs], body)
expr = ap e [if i == conTag con then receiver else eError
| i <- [1..(tyconNumCon $ conTycon con)]]
eError = Ap (Var "error") (Lit $ LitStr $ "!?")
type Equation = Alt
isVar :: Equation -> Bool
isVar (p:_, _) = test p
where test (PVar _) = True
test PWildcard = True
test (PAs _ p) = test p
test (PLit _) = False
test (PCon _ _) = False
partitionEqns :: Eq b => (a -> b) -> [a] -> [[a]]
partitionEqns f [] = []
partitionEqns f [x] = [[x]]
partitionEqns f (x:xs@(x':_)) | f x == f x' = tack x (partitionEqns f xs)
| otherwise = [x] : partitionEqns f xs
tack x xss = (x : head xss) : tail xss
match :: [Id] -> [Equation] -> Expr -> PatComp Expr
match [] qs def = foldrM pcRhs def (map snd qs)
match us qs def =
foldrM (matchVarCon us) def (partitionEqns isVar qs)
matchVarCon :: [Id] -> [Equation] -> Expr -> PatComp Expr
matchVarCon us@(u:_) qs def =
case head $ fst $ head qs' of
PLit _ -> bindDefault (matchLit us qs') def
PCon _ _ -> bindDefault (matchCon us qs') def
_ -> matchVar us qs' def
where qs' = map sub qs
sub (PAs v p : ps, rhs) = sub (p:ps, Where (bind1 v (Var u)) rhs)
sub (ps, rhs) = (ps, rhs)
matchVar :: [Id] -> [Equation] -> Expr -> PatComp Expr
matchVar (u:us) qs def = match us (map sub qs) def
where sub (PVar v : ps, rhs) = (ps, Where (bind1 v (Var u)) rhs)
sub (PWildcard : ps, rhs) = (ps, rhs)
bindDefault :: (Expr -> PatComp Expr) -> Expr -> PatComp Expr
bindDefault f def
| simple def = f def
| otherwise = do v <- newVar
e <- f (Var v)
return $ Let (bind1 v def) e
where simple _ = True
{- これでは効率悪い -- 式のサイズで分けるとか?
where simple (Var _) = True
simple (Lit _) = True
simple (Con _) = True
simple _ = False
-}
matchLit :: [Id] -> [Equation] -> Expr -> PatComp Expr
matchLit us qs def =
do clauses <- mapM (matchLitClause us def) (groupLit qs)
return $ foldr makeIf def clauses
matchLitClause :: [Id] -> Expr -> (Literal, [Equation]) -> PatComp (Expr, Expr)
matchLitClause (u:us) def (lit, qs) =
do e <- match us [(ps,rhs) | (_:ps,rhs)<-qs] def
return (ap (Var "&eq") [Var u, Lit lit], e)
groupLit :: [Equation] -> [(Literal, [Equation])]
groupLit [] = []
groupLit qs@((PLit l:_,_):_) = (l, qs') : groupLit qs''
where (qs', qs'') = partition (\(PLit l':_,_) -> l == l') qs
matchCon :: [Id] -> [Equation] -> Expr -> PatComp Expr
matchCon us qs def
| isCovered grps =
do clauses <- mapM (matchConClause us def) (init grps)
lastClause <- matchConLastClause us def (last grps)
return $ foldr makeIf lastClause clauses
| otherwise =
do clauses <- mapM (matchConClause us def) grps
return $ foldr makeIf def clauses
where grps = groupCon qs
{- matchConClause [a,b] def ((:), [([: x xs, y], rhs)])
=> (TAGEQ (:) a, let v1 = SEL 1 a, v2 = SEL 2 a in
(match [v1,v2,b] [([x,xs,y],rhs)] def)
=> (TAGEQ (:) a, a (\v1 v2 -> (match [v1,v2,b] [([x,xs,y],rhs)] def)) error)
-}
matchConClause :: [Id] -> Expr -> (Const, [Equation]) -> PatComp (Expr, Expr)
matchConClause (u:us) def (con, qs) =
do us' <- newVars k'
body <- match (us'++us)
[(ps'++ps, rhs) | (PCon c ps':ps, rhs) <- qs] def
let receiver = Lambda ([PVar v | v <- us'], Rhs body)
expr = ap (Var u) [if i == conTag con then receiver else eError
| i <- [1..(tyconNumCon $ conTycon con)]]
in return (cond, expr)
where cond = makeTagEq con (Var u)
k' = conArity con
eError = Ap (Var "error") (Lit $ LitStr $ "!?")
matchConLastClause :: [Id] -> Expr -> (Const, [Equation]) -> PatComp Expr
matchConLastClause us def grp = do (_, e) <- matchConClause us def grp
return e
groupCon :: [Equation] -> [(Const, [Equation])]
groupCon [] = []
groupCon qs@((PCon c _:_,_):_) = (c, qs') : groupCon qs''
where (qs', qs'') = partition (\(PCon c' _:_,_) -> c == c') qs
isCovered :: [(Const, [Equation])] -> Bool
isCovered grps = n == 0 || length grps == n
where n = tyconNumCon $ conTycon $ fst $ head grps
newVars :: Int -> PatComp [Id]
newVars k = do n <- get
put (n+k)
return ['@':show (n+i) | i <- [1..k]]
newVar :: PatComp Id
newVar = do n <- get
put (n+1)
return $ '@':show (n+1)
makeIf :: (Expr, Expr) -> Expr -> Expr
makeIf (c, e) e' = ap (Var "IF") [c, e, e']
{- makeTagEq (:) e => e (\x -> \xs -> True) False
-}
makeTagEq :: Const -> Expr -> Expr
--makeTagEq con e = ap (Var "TAGEQ") [Con con, e]
makeTagEq con e = ap e es
where arities = tyconArities (conTycon con)
es = [test a (b == conTag con) | (a, b) <- zip arities [1..]]
test arity b =
Lambda ([PVar ('_':show n) | n <- [1..arity]],
Rhs $ if b then eTrue else eFalse)
bind1 :: Id -> Expr -> BindGroup
bind1 v e = ([], [[(v, [([], Rhs e)])]])
foldrM :: Monad m => (b -> a -> m a) -> a -> [b] -> m a
foldrM f a xs = foldM (flip f) a (reverse xs)