1 {-# LANGUAGE PatternSynonyms #-} -- For Comb
2 {-# LANGUAGE TemplateHaskell #-} -- For branch
3 {-# LANGUAGE ViewPatterns #-} -- For unSomeComb
4 {-# OPTIONS_GHC -fno-warn-orphans #-} -- For MakeLetName TH.Name
5 -- | Bottom-up optimization of 'Comb'inators,
6 -- reexamining downward as needed after each optimization.
7 module Symantic.Parser.Grammar.Optimize where
9 import Data.Bool (Bool(..))
10 import Data.Either (Either(..), either)
11 import Data.Eq (Eq(..))
12 import Data.Function ((.))
13 import Data.Maybe (Maybe(..))
14 import qualified Data.Functor as Functor
15 import qualified Data.Foldable as Foldable
16 import qualified Data.List as List
17 import qualified Language.Haskell.TH.Syntax as TH
18 import Data.Kind (Constraint, Type)
19 import Type.Reflection (Typeable, typeRep, eqTypeRep, (:~~:)(..))
21 import Symantic.Parser.Grammar.Combinators as Comb
22 import Symantic.Parser.Haskell ()
23 import Symantic.Univariant.Letable
24 import Symantic.Univariant.Trans
25 import qualified Symantic.Parser.Haskell as H
27 {- Uncomment to trace optimizations
28 import Data.Function (($), flip)
29 import Debug.Trace (trace)
35 -- * Type 'OptimizeGrammar'
36 type OptimizeGrammar = SomeComb
39 Trans (SomeComb repr) repr =>
40 SomeComb repr a -> repr a
41 optimizeGrammar = trans
43 -- * Data family 'Comb'
44 -- | 'Comb'uctions for the 'Machine'.
45 -- This is an extensible data-type.
47 (comb :: ReprComb -> Constraint)
51 -- | Convenient utility to pattern-match a 'SomeComb'.
52 pattern Comb :: Typeable comb =>
55 pattern Comb x <- (unSomeComb -> Just x)
58 type ReprComb = Type -> Type
61 -- | Some 'Comb'inator existentialized over the actual combinator symantic class.
62 -- Useful to handle a list of 'Comb'inators
63 -- without requiring impredicative quantification.
64 -- Must be used by pattern-matching
65 -- on the 'SomeComb' data-constructor,
66 -- to bring the constraints in scope.
68 -- The optimizations are directly applied within it,
69 -- to avoid introducing an extra newtype,
70 -- this also give a more comprehensible code.
71 data SomeComb repr a =
73 (Trans (Comb comb repr) repr, Typeable comb) =>
74 SomeComb (Comb comb repr a)
76 instance Trans (SomeComb repr) repr where
77 trans (SomeComb x) = trans x
79 -- | @(unSomeComb c :: 'Maybe' ('Comb' comb repr a))@
80 -- extract the data-constructor from the given 'SomeComb'
81 -- iif. it belongs to the @('Comb' comb repr a)@ data-instance.
85 SomeComb repr a -> Maybe (Comb comb repr a)
86 unSomeComb (SomeComb (c::Comb c repr a)) =
87 case typeRep @comb `eqTypeRep` typeRep @c of
92 data instance Comb Applicable repr a where
93 Pure :: TermGrammar a -> Comb Applicable repr a
94 (:<*>:) :: SomeComb repr (a -> b) -> SomeComb repr a -> Comb Applicable repr b
95 (:<*:) :: SomeComb repr a -> SomeComb repr b -> Comb Applicable repr a
96 (:*>:) :: SomeComb repr a -> SomeComb repr b -> Comb Applicable repr b
97 infixl 4 :<*>:, :<*:, :*>:
98 pattern (:<$>:) :: TermGrammar (a -> b) -> SomeComb repr a -> Comb Applicable repr b
99 pattern t :<$>: x <- Comb (Pure t) :<*>: x
100 pattern (:$>:) :: SomeComb repr a -> TermGrammar b -> Comb Applicable repr b
101 pattern x :$>: t <- x :*>: Comb (Pure t)
102 instance Applicable repr => Trans (Comb Applicable repr) repr where
104 Pure x -> pure (H.optimizeTerm x)
105 f :<*>: x -> trans f <*> trans x
106 x :<*: y -> trans x <* trans y
107 x :*>: y -> trans x *> trans y
114 ) => Applicable (SomeComb repr) where
115 pure = SomeComb . Pure
116 f <$> Comb (Branch b l r) =
120 -- & trace "Branch Distributivity Law"
121 f <$> Comb (Conditional a ps bs d) =
123 ((f <$>) Functor.<$> bs)
125 -- & trace "Conditional Distributivity Law"
126 -- Being careful here to use (<*>),
127 -- instead of SomeComb (f <$> unOptComb x),
128 -- in order to apply the optimizations of (<*>).
129 f <$> x = pure f <*> x
132 -- & trace "Commutativity Law"
134 Comb Empty <*> _ = empty
135 -- & trace "App Right Absorption Law"
136 u <*> Comb Empty = u *> empty
137 -- & trace "App Failure Weakening Law"
138 Comb (Pure f) <*> Comb (Pure x) = pure (f H..@ x)
139 -- & trace "Homomorphism Law"
140 Comb (Pure f) <*> Comb (g :<$>: p) =
141 -- This is basically a shortcut,
142 -- it can be caught by the Composition Law
143 -- and Homomorphism Law.
144 (H..) H..@ f H..@ g <$> p
145 -- & trace "Functor Composition Law"
146 u <*> Comb (v :<*>: w) = (((H..) <$> u) <*> v) <*> w
147 -- & trace "Composition Law"
148 u <*> Comb (Pure x) = H.flip H..@ (H.$) H..@ x <$> u
149 -- & trace "Interchange Law"
150 Comb (u :*>: v) <*> w = u *> (v <*> w)
151 -- & trace "Reassociation Law 1"
152 u <*> Comb (v :<*: w) = (u <*> v) <* w
153 -- & trace "Reassociation Law 2"
154 u <*> Comb (v :$>: x) = (u <*> pure x) <* v
155 -- & trace "Reassociation Law 3"
156 p <*> Comb (NegLook q) =
157 (p <*> pure H.unit) <* negLook (q)
158 -- & trace "Absorption Law"
159 x <*> y = SomeComb (x :<*>: y)
161 Comb Empty *> _ = empty
162 -- & trace "App Right Absorption Law"
163 Comb (_ :<$>: p) *> q = p *> q
164 -- & trace "Right Absorption Law"
166 -- & trace "Identity Law"
167 Comb (u :$>: _) *> v = u *> v
168 -- & trace "Identity Law"
169 u *> Comb (v :*>: w) = (u *> v) *> w
170 -- & trace "Associativity Law"
171 x *> y = SomeComb (x :*>: y)
173 Comb Empty <* _ = empty
174 -- & trace "App Right Absorption Law"
175 u <* Comb Empty = u *> empty
176 -- & trace "App Failure Weakening Law"
177 p <* Comb (_ :<$>: q) = p <* q
178 -- & trace "Left Absorption Law"
180 -- & trace "Identity Law"
181 u <* Comb (v :$>: _) = u <* v
182 -- & trace "Identity Law"
183 Comb (u :<*: v) <* w = u <* (v <* w)
184 -- & trace "Associativity Law"
185 x <* y = SomeComb (x :<*: y)
188 data instance Comb Alternable repr a where
189 Empty :: Comb Alternable repr a
190 (:<|>:) :: SomeComb repr a -> SomeComb repr a -> Comb Alternable repr a
191 Try :: SomeComb repr a -> Comb Alternable repr a
193 instance Alternable repr => Trans (Comb Alternable repr) repr where
196 f :<|>: x -> trans f <|> trans x
197 Try x -> try (trans x)
204 ) => Alternable (SomeComb repr) where
205 empty = SomeComb Empty
207 p@(Comb Pure{}) <|> _ = p
208 -- & trace "Left Catch Law"
210 -- & trace "Left Neutral Law"
212 -- & trace "Right Neutral Law"
213 Comb (u :<|>: v) <|> w = u <|> (v <|> w)
214 -- & trace "Associativity Law"
215 Comb (Look p) <|> Comb (Look q) = look (try p <|> q)
216 -- & trace "Distributivity Law"
217 x <|> y = SomeComb (x :<|>: y)
219 try (Comb (p :$>: x)) = try p $> x
220 -- & trace "Try Interchange Law"
221 try (Comb (f :<$>: p)) = f <$> try p
222 -- & trace "Try Interchange Law"
223 try x = SomeComb (Try x)
226 data instance Comb Selectable repr a where
228 SomeComb repr (Either a b) ->
229 SomeComb repr (a -> c) ->
230 SomeComb repr (b -> c) ->
231 Comb Selectable repr c
232 instance Selectable repr => Trans (Comb Selectable repr) repr where
234 Branch lr l r -> branch (trans lr) (trans l) (trans r)
241 ) => Selectable (SomeComb repr) where
242 branch (Comb Empty) _ _ = empty
243 -- & trace "Branch Absorption Law"
244 branch b (Comb Empty) (Comb Empty) = b *> empty
245 -- & trace "Branch Weakening Law"
246 branch (Comb (Pure (trans -> lr))) l r =
248 Left value -> l <*> pure (trans H.ValueCode{..})
249 where code = [|| case $$(H.code lr) of Left x -> x ||]
250 Right value -> r <*> pure (trans H.ValueCode{..})
251 where code = [|| case $$(H.code lr) of Right x -> x ||]
252 -- & trace "Branch Pure Left/Right Law" $
253 branch b (Comb (Pure (trans -> l))) (Comb (Pure (trans -> r))) =
254 trans H.ValueCode{..} <$> b
255 -- & trace "Branch Generalised Identity Law"
257 value = either (H.value l) (H.value r)
258 code = [|| either $$(H.code l) $$(H.code r) ||]
259 branch (Comb (x :*>: y)) p q = x *> branch y p q
260 -- & trace "Interchange Law"
261 branch b l (Comb Empty) =
262 branch (pure (trans (H.ValueCode{..})) <*> b) empty l
263 -- & trace "Negated Branch Law"
265 value = either Right Left
266 code = [||either Right Left||]
267 branch (Comb (Branch b (Comb Empty) (Comb (Pure (trans -> lr))))) (Comb Empty) br =
268 branch (pure (trans H.ValueCode{..}) <*> b) empty br
269 -- & trace "Branch Fusion Law"
271 value Left{} = Left ()
272 value (Right r) = case H.value lr r of
275 code = [|| \case Left{} -> Left ()
276 Right r -> case $$(H.code lr) r of
278 Right rr -> Right rr ||]
279 branch b l r = SomeComb (Branch b l r)
282 data instance Comb Matchable repr a where
283 Conditional :: Eq a =>
285 [TermGrammar (a -> Bool)] ->
288 Comb Matchable repr b
289 instance Matchable repr => Trans (Comb Matchable repr) repr where
291 Conditional a ps bs b -> conditional (trans a) ps (trans Functor.<$> bs) (trans b)
298 ) => Matchable (SomeComb repr) where
299 conditional (Comb Empty) _ _ d = d
300 -- & trace "Conditional Absorption Law"
301 conditional p _ qs (Comb Empty)
302 | Foldable.all (\case { Comb Empty -> True; _ -> False }) qs = p *> empty
303 -- & trace "Conditional Weakening Law"
304 conditional a _ps bs (Comb Empty)
305 | Foldable.all (\case { Comb Empty -> True; _ -> False }) bs = a *> empty
306 -- & trace "Conditional Weakening Law"
307 conditional (Comb (Pure (trans -> a))) ps bs d =
308 Foldable.foldr (\(trans -> p, b) next ->
309 if H.value p (H.value a) then b else next
311 -- & trace "Conditional Pure Law"
312 conditional a ps bs d = SomeComb (Conditional a ps bs d)
315 data instance Comb Foldable repr a where
316 ChainPreC :: SomeComb repr (a -> a) -> SomeComb repr a -> Comb Foldable repr a
317 ChainPostC :: SomeComb repr a -> SomeComb repr (a -> a) -> Comb Foldable repr a
318 instance Foldable repr => Trans (Comb Foldable repr) repr where
320 ChainPreC x y -> chainPre (trans x) (trans y)
321 ChainPostC x y -> chainPost (trans x) (trans y)
322 instance Foldable repr => Foldable (SomeComb repr) where
323 chainPre x = SomeComb . ChainPreC x
324 chainPost x = SomeComb . ChainPostC x
327 data instance Comb Lookable repr a where
328 Look :: SomeComb repr a -> Comb Lookable repr a
329 NegLook :: SomeComb repr a -> Comb Lookable repr ()
330 Eof :: Comb Lookable repr ()
331 instance Lookable repr => Trans (Comb Lookable repr) repr where
333 Look x -> look (trans x)
334 NegLook x -> negLook (trans x)
342 ) => Lookable (SomeComb repr) where
343 look p@(Comb Pure{}) = p
344 -- & trace "Pure Look Law"
345 look p@(Comb Empty) = p
346 -- & trace "Dead Look Law"
347 look (Comb (Look x)) = look x
348 -- & trace "Idempotence Law"
349 look (Comb (NegLook x)) = negLook x
350 -- & trace "Left Identity Law"
351 look (Comb (p :$>: x)) = look p $> x
352 -- & trace "Interchange Law"
353 look (Comb (f :<$>: p)) = f <$> look p
354 -- & trace "Interchange Law"
355 look x = SomeComb (Look x)
357 negLook (Comb Pure{}) = empty
358 -- & trace "Pure Negative-Look"
359 negLook (Comb Empty) = pure H.unit
360 -- & trace "Dead Negative-Look"
361 negLook (Comb (NegLook x)) = look (try x *> pure H.unit)
362 -- & trace "Double Negation Law"
363 negLook (Comb (Try x)) = negLook x
364 -- & trace "Zero Consumption Law"
365 negLook (Comb (Look x)) = negLook x
366 -- & trace "Right Identity Law"
367 negLook (Comb (Comb (Try p) :<|>: q)) = negLook p *> negLook q
368 -- & trace "Transparency Law"
369 negLook (Comb (p :$>: _)) = negLook p
370 -- & trace "NegLook Idempotence Law"
371 negLook x = SomeComb (NegLook x)
376 data instance Comb (Satisfiable tok) repr a where
378 Satisfiable tok repr =>
380 TermGrammar (tok -> Bool) ->
381 Comb (Satisfiable tok) repr tok
383 Satisfiable tok repr =>
384 Comb (Satisfiable tok) repr tok
385 instance Satisfiable tok repr => Trans (Comb (Satisfiable tok) repr) repr where
387 Satisfy es p -> satisfy es p
390 (Satisfiable tok repr, Typeable tok) =>
391 Satisfiable tok (SomeComb repr) where
392 satisfy es = SomeComb . Satisfy es
396 data instance Comb (Letable letName) repr a where
397 Def :: letName -> SomeComb repr a -> Comb (Letable letName) repr a
398 Ref :: Bool -> letName -> Comb (Letable letName) repr a
399 instance Letable letName repr => Trans (Comb (Letable letName) repr) repr where
401 Def n v -> def n (trans v)
402 Ref isRec n -> ref isRec n
404 (Letable letName repr, Typeable letName) =>
405 Letable letName (SomeComb repr) where
406 def n = SomeComb . Def n
407 ref isRec = SomeComb . Ref isRec
408 instance MakeLetName TH.Name where
409 makeLetName _ = TH.qNewName "name"