1 {-# LANGUAGE DerivingStrategies #-}
3 {-# LANGUAGE QuantifiedConstraints #-}
5 {-# LANGUAGE UndecidableInstances #-}
7 module Symantic.Semantics.LetInserter where
9 import Control.Applicative (liftA2, liftA3)
10 import Control.Monad (Monad (..))
11 import Control.Monad.Trans.State.Strict qualified as MT
12 import Data.Bool (Bool (..), not, otherwise, (&&))
13 import Data.Either (Either (..))
14 import Data.Eq (Eq (..))
15 import Data.Foldable (foldMap)
16 import Data.Function (const, id, on, ($), (.))
17 import Data.Functor ((<$>))
19 import Data.Kind (Type)
20 import Data.List qualified as List
21 import Data.Maybe (Maybe (..), isNothing, maybe)
22 import Data.Ord (Ord (..))
23 import Data.Semigroup (Semigroup (..))
24 import Data.Set qualified as Set
25 import Debug.Trace qualified as Trace
26 import Numeric.Natural (Natural)
27 import Symantic.Syntaxes.Classes qualified as Syn
28 import Symantic.Syntaxes.Derive qualified as Syn
29 import Text.Show (Show (..), showListWith, showString, shows)
30 import Unsafe.Coerce (unsafeCoerce)
31 import Prelude (error, pred)
32 import Prelude qualified
34 -- import Control.Monad.Trans.Class qualified as MT
35 -- import Data.Functor.Identity (Identity(..))
36 -- import Data.Monoid (Monoid(..))
37 -- import Data.String (String)
39 traceShow :: Show a => a -> b -> b
40 -- traceShow = Trace.traceShow
43 newtype Locus = Locus Natural
45 deriving newtype (Show)
49 data Pigit = POne | PTwo | PThree | PLoc Locus | PNote String
51 instance Show Pigit where
54 POne -> shows (1::Int)
55 PTwo -> shows (2::Int)
56 PThree -> shows (3::Int)
58 PNote msg -> showString msg
62 newtype OpenCode code a = OpenCode {unOpenCode :: Env code -> code a}
63 type instance Syn.Derived (OpenCode code) = code
65 -- instance Syn.Derivable (OpenCode code) where
66 -- derive oc = unOpenCode oc mempty
67 instance Syn.LiftDerived (OpenCode code) where
68 liftDerived x = OpenCode (const x)
69 instance Syn.LiftDerived1 (OpenCode code) where
70 liftDerived1 f x = OpenCode (\env -> f (unOpenCode x env))
71 instance Syn.LiftDerived2 (OpenCode code) where
72 liftDerived2 f x y = OpenCode (\env -> f (unOpenCode x env) (unOpenCode y env))
73 instance Syn.LiftDerived3 (OpenCode code) where
74 liftDerived3 f x y z = OpenCode (\env -> f (unOpenCode x env) (unOpenCode y env) (unOpenCode z env))
76 -- instance Syn.Abstractable code => Syn.Abstractable (OpenCode code) where
77 -- lam f = OpenCode (\env -> Syn.lam (\x -> unOpenCode f env (unOpenCode x env)))
78 -- instance Syn.Instantiable code => Syn.Instantiable (OpenCode code)
79 -- instance Syn.Constantable c code => Syn.Constantable c (OpenCode code)
80 instance Syn.IfThenElseable code => Syn.IfThenElseable (OpenCode code) where
81 ifThenElse x y z = OpenCode (\env -> Syn.ifThenElse (unOpenCode x env) (unOpenCode y env) (unOpenCode z env))
82 instance Syn.Equalable code => Syn.Equalable (OpenCode code) where
83 equal = OpenCode (const Syn.equal)
84 instance Syn.Constantable c code => Syn.Constantable c (OpenCode code)
87 type Env code = [EnvBind code]
90 newtype Var a = Var {unVar :: VarName}
92 deriving newtype (Show)
96 data EnvBind code where
97 EnvBind :: !(Var a, code a) -> EnvBind code
98 instance Show (EnvBind code) where
99 showsPrec p (EnvBind (n, _e)) = showsPrec p n
101 lookupVar :: Var a -> OpenCode code a
103 traceShow (["lookupVar", "OpenCode"], v) $
105 traceShow (["lookupVar", "OpenCode", "find"], v, ("env", env)) $
106 case List.find (\(EnvBind (Var v1, _)) -> v1 == v) env of
107 Just (EnvBind (_, x)) -> unsafeCoerce x
108 Nothing -> error ("lookupVar failure for var=(" <> show v <> ") env=" <> show ((\(EnvBind (Var n, _v)) -> n) <$> env))
110 lookupVarLetInserter :: Var a -> LetInserter code a
111 lookupVarLetInserter v =
115 { annotatedCodeOpenCode = lookupVar v
116 , annotatedCodeFloatingLets = FloatingLets []
117 , annotatedCodeFreeVars = Set.singleton (unVar v)
120 insertVar :: Var a -> code a -> Env code -> Env code
122 traceShow ("insertVar", v) $
128 -- ** Type 'MaybeMemo'
130 -- | Like a @(Maybe Memo)@ except 'Nothing' is never equal to any other value
131 -- to implement unique memoization key.
132 newtype MaybeMemo = MaybeMemo (Maybe Memo)
135 instance Eq MaybeMemo where
136 MaybeMemo (Just x) == MaybeMemo (Just y) = x == y
139 -- * Type 'FloatingLet'
140 data FloatingLet code where
142 { floatingLetLocus :: !(Maybe Locus)
143 -- ^ 'FloatingLet' are either inserted at the place of an explicit 'Locus',
144 -- or at the binding ('lam' or 'let_') that dominates all free variables of the bound expression,
145 -- whichever has the narrowest scope.
146 , floatingLetMemo :: !MaybeMemo
147 -- ^ Memoization key, either internal (unique) or user-specified.
149 -- The memo key defines the equivalence classes:
150 -- expressions with the same memo key are to be shared.
151 -- Therefore, if @('genLetMemo' k l e)@ finds that there is already a let-binding
152 -- produced by an earlier 'genLetMemo' with the same locus @(l)@ and the same memo key @(k)@,
153 -- @('genLetMemo' k l e) returns the code of the earlier bound variable.
154 , floatingLetVarName :: !(Var a)
155 , floatingLetBoundCode :: !(BoundCode code a)
156 , floatingLetFreeVars :: !(Set.Set VarName)
159 instance Show (FloatingLet code) where
160 showsPrec _p FloatingLet{..} =
161 showString "FloatingLet{"
162 . showString "locus="
163 . shows floatingLetLocus
166 . shows floatingLetMemo
169 . shows floatingLetVarName
172 . showString (case floatingLetBoundCode of BoundCodeOpenCode{} -> "BoundCodeOpenCode"; BoundCodeLetInserter{} -> "BoundCodeLetInserter")
175 . showListWith (shows) (Set.toList floatingLetFreeVars)
179 -- * Type 'VLBindings'
181 -- A virtual let-binding.
182 -- The key idea is virtual let-bindings: whereas clet introduces an ordinary let-binding
183 -- whose location is fixed, glet generates the code for a fresh variable accompanied by a virtual
184 -- binding of that variable. Virtual bindings do not have (yet) a fixed location: they are
185 -- attached to the expression that uses their bound variables and ‘float up’ when their attached
186 -- expression is incorporated into a bigger expression. Eventually, when they reach a point that
187 -- a metaprogrammer has marked with a dedicated primitive, virtual bindings are converted to
188 -- real let-bindings.
189 newtype FloatingLets code = FloatingLets {unFloatingLets :: [FloatingLet code]}
190 instance Show (FloatingLets code) where
191 showsPrec _p (FloatingLets l) = go l
193 go [] = showString "\n"
194 go (e : es) = showString "\n , " . shows e . go es
196 -- | Append two lists skipping the duplicates.
197 -- The order of elements is preserved
198 mergeFloatingLets :: FloatingLets code -> FloatingLets code -> FloatingLets code
199 mergeFloatingLets (FloatingLets xs) (FloatingLets ys) =
200 traceShow (["mergeFloatingLets"], xs, ys) $
201 FloatingLets (loop (List.reverse xs) ys)
204 [] -> List.reverse acc
205 y@FloatingLet{floatingLetVarName = Var yv} : t ->
207 ( \a@FloatingLet{floatingLetVarName = Var av} ->
208 floatingLetLocus y == floatingLetLocus a
209 && floatingLetMemo y == floatingLetMemo a
213 [] -> loop (y : acc) t
217 -- loop (List.concatMap (\FloatingLet{floatingLetBoundCode, floatingLetLocus, floatingLetMemo, floatingLetVarName=Var av} ->
220 -- FloatingLet { floatingLetVarName=Var yv, .. }) fs <> acc) t
221 instance Semigroup (FloatingLets code) where
222 (<>) = mergeFloatingLets
224 -- instance Monoid (FloatingLets code) where
225 -- mempty = FloatingLets []
228 -- * Type 'BoundCode'
230 -- | Bound expression
231 data BoundCode (code :: Type -> Type) a
232 = BoundCodeOpenCode !(OpenCode code a)
233 | -- | In the recursive case,
234 -- a virtual binding may carry a yet to be computed piece of code.
235 BoundCodeLetInserter !(LetInserter code a)
237 -- * Type 'AnnotatedCode'
240 -- A code value is annotated only with the type of the expression it generates,
241 -- with no further classifiers (at present).
242 data AnnotatedCode (code :: Type -> Type) a = AnnotatedCode
243 { annotatedCodeOpenCode :: !(OpenCode code a)
244 , annotatedCodeFloatingLets :: !(FloatingLets code)
245 , annotatedCodeFreeVars :: !(Set.Set VarName)
246 -- ^ The free variables of the code,
247 -- used to limit the floating up of locus-less 'FloatingLet's
248 -- at 'lam' or 'let_' level, in order to avoid scope extrusion.
251 -- annotatedCodeFreeVars :: AnnotatedCode code a -> Set.Set VarName
252 -- annotatedCodeFreeVars annotatedCode = foldMap floatingLetFreeVars (unFloatingLets (annotatedCodeFloatingLets annotatedCode))
254 runCD :: Syn.Letable code => AnnotatedCode code a -> code a
255 runCD AnnotatedCode{annotatedCodeOpenCode = oc, annotatedCodeFloatingLets = FloatingLets bindingFLS} =
256 let bindingLFSByMemo = groupBy ((==) `on` floatingLetMemo) bindingFLS
257 in (`unOpenCode` []) $ List.foldr bindFloatingLetMemo oc bindingLFSByMemo
258 runCD _ = error "runCD: virtual binding extrusion"
260 type instance Syn.Derived (AnnotatedCode code) = OpenCode code
261 instance Syn.LiftDerived (AnnotatedCode code) where
262 liftDerived x = AnnotatedCode{annotatedCodeOpenCode = x, annotatedCodeFloatingLets = FloatingLets [], annotatedCodeFreeVars = Set.empty}
263 instance Syn.LiftDerived1 (AnnotatedCode code) where
266 { annotatedCodeOpenCode = f (annotatedCodeOpenCode e1)
267 , annotatedCodeFloatingLets = annotatedCodeFloatingLets e1
268 , annotatedCodeFreeVars = annotatedCodeFreeVars e1
270 instance Syn.LiftDerived2 (AnnotatedCode code) where
271 liftDerived2 f e1 e2 =
273 { annotatedCodeOpenCode = f (annotatedCodeOpenCode e1) (annotatedCodeOpenCode e2)
274 , annotatedCodeFloatingLets = mergeFloatingLets (annotatedCodeFloatingLets e1) (annotatedCodeFloatingLets e2)
275 , annotatedCodeFreeVars = annotatedCodeFreeVars e1 <> annotatedCodeFreeVars e2
277 instance Syn.LiftDerived3 (AnnotatedCode code) where
278 liftDerived3 f e1 e2 e3 =
280 { annotatedCodeOpenCode = f (annotatedCodeOpenCode e1) (annotatedCodeOpenCode e2) (annotatedCodeOpenCode e3)
281 , annotatedCodeFloatingLets = mergeFloatingLets (annotatedCodeFloatingLets e1) (mergeFloatingLets (annotatedCodeFloatingLets e2) (annotatedCodeFloatingLets e3))
282 , annotatedCodeFreeVars = annotatedCodeFreeVars e1 <> annotatedCodeFreeVars e2 <> annotatedCodeFreeVars e3
284 instance Syn.Constantable c code => Syn.Constantable c (AnnotatedCode code)
285 instance Syn.Instantiable code => Syn.Instantiable (AnnotatedCode code)
286 instance Syn.IfThenElseable code => Syn.IfThenElseable (AnnotatedCode code)
287 instance Syn.Equalable code => Syn.Equalable (AnnotatedCode code)
289 -- * Type 'LetInserter'
290 newtype LetInserter code a = LetInserter {unR :: MT.State Natural (AnnotatedCode code a)}
291 runLetInserter :: Syn.Letable code => LetInserter code a -> code a
292 runLetInserter = runCD . (`MT.evalState` 0) . unR
294 type instance Syn.Derived (LetInserter code) = AnnotatedCode code
295 instance Syn.LiftDerived (LetInserter sem) where
296 liftDerived = LetInserter . return
297 instance Syn.LiftDerived1 (LetInserter sem) where
298 liftDerived1 f e1 = LetInserter (f <$> unR e1)
299 instance Syn.LiftDerived2 (LetInserter sem) where
300 liftDerived2 f e1 e2 = LetInserter (liftA2 f (unR e1) (unR e2))
301 instance Syn.LiftDerived3 (LetInserter sem) where
302 liftDerived3 f e1 e2 e3 = LetInserter (liftA3 f (unR e1) (unR e2) (unR e3))
303 instance Syn.IfThenElseable code => Syn.IfThenElseable (LetInserter code)
304 instance Syn.Equalable code => Syn.Equalable (LetInserter code)
305 instance Syn.Constantable c code => Syn.Constantable c (LetInserter code)
306 instance Syn.Instantiable code => Syn.Instantiable (OpenCode code)
308 freshNatural :: MT.State Natural Natural
311 MT.put (Prelude.succ n)
314 -- type instance Syn.Derived (LetInserter sem) = Syn.Derived sem
315 freshVar :: MT.State Natural (Var a)
316 freshVar = Var . Locus <$> freshNatural
318 -- instance Syn.Constantable c sem => Syn.Constantable c (LetInserter sem) where
319 -- constant c = LetInserter $ pure $ Syn.constant c
320 instance Syn.Instantiable sem => Syn.Instantiable (LetInserter sem)
322 -- f .@ x = LetInserter $ Syn.liftDerived2 (Syn..@) (unR f) (unR x)
323 -- instance Syn.Abstractable sem => Syn.Abstractable (LetInserter sem) where
324 -- lam f = LetInserter $ \loc ->
326 -- unR (f (LetInserter (\_loc -> x)))
328 -- instance Syn.Abstractable code => Syn.Abstractable (LetInserter (AnnotatedCode code)) where
329 -- lam body = LetInserter $ \loc ->
331 -- { annotatedCodeOpenCode = _e
333 -- -- \x -> unR (body (LetInserter (\_ -> x))) (PNote "lam":loc)
334 -- instance Syn.Letable (LetInserter sem) where
335 -- let_ exp body = LetInserter $ \loc ->
336 -- let x = unR exp (POne:loc) in
337 -- unR (body (LetInserter (\_loc -> x))) (PTwo:loc)
339 -- instance Syn.Letable code => Syn.Letable (LetInserter code) where
340 -- let_ e body = LetInserter $ \loc ->
341 -- let x = unR e (POne:loc) in
342 -- unR (body (LetInserter (\_loc -> x))) (PTwo:loc)
344 -- instance Syn.Letable (LetInserter sem) where
345 -- let_ exp body = LetInserter (\loc -> let x = unR exp (POne:loc) in unR (body (LetInserter (\_loc -> x))) (PTwo:loc))
346 -- instance Syn.IfThenElseable code => Syn.IfThenElseable (LetInserter (AnnotatedCode code)) where
348 -- Syn.liftDerived3 $ \bC okC koC -> OpenCode $ \env ->
349 -- Syn.ifThenElse (unOpenCode bC env) (unOpenCode okC env) (unOpenCode koC env)
350 -- instance Syn.FromDerived Syn.Equalable sem => Syn.Equalable (LetInserter sem) where
351 -- equal = LetInserter (\loc -> trace ("equal "<>show loc) $ Syn.equal)
353 -- | Check to see there are no duplicate 'VarName's in 'VLBindings'.
354 -- This is just a safety check
355 check_no_dup_varname :: FloatingLets code -> a -> a
356 check_no_dup_varname = loop []
358 loop :: [VarName] -> FloatingLets code -> a -> a
359 loop _found (FloatingLets []) = id
360 loop found (FloatingLets (FloatingLet{floatingLetVarName = Var v, ..} : t))
361 | v `List.elem` found =
362 error ("Duplicate varname " <> show v <> ", with locus " <> show floatingLetLocus)
363 | otherwise = loop (v : found) (FloatingLets t)
365 -- | let-bind all vlbindings with the given locus.
366 -- This is a non-recursive case. All these let-bindings are independent
367 -- It is up to the user to ensure the independence: if the bindings
368 -- are dependent, the user should have introduced several loci
369 -- Virtual let bindings are sort of free variables.
370 -- We bind free variables later. Likewise, we bind let-bindings later.
371 -- 'Memo' is ignored here.
372 -- class GenLetable sem where
373 -- instance Syn.Letable code => GenLetable (LetInserter (AnnotatedCode code)) where
374 floatingLetVarname :: FloatingLet code -> VarName
375 floatingLetVarname FloatingLet{floatingLetVarName = Var v} = v
378 ( Syn.Abstractable code
380 , Syn.LetRecable Int code
382 Syn.Abstractable (LetInserter code)
384 lam body = LetInserter $ do
389 let (bindingFLS, passingFLS) =
391 (\fl -> Set.member (unVar vname) (floatingLetFreeVars fl))
392 (unFloatingLets (annotatedCodeFloatingLets bodyCD))
393 in let bindingLFSByMemo = groupBy ((==) `on` floatingLetMemo) bindingFLS
396 , ("vname", unVar vname)
397 , ("bindingFLS", FloatingLets bindingFLS)
398 , ("passingFLS", FloatingLets passingFLS)
399 , ("bodyFreeVars", annotatedCodeFreeVars bodyCD)
400 , ("annotatedCodeFloatingLets bodyCD", annotatedCodeFloatingLets bodyCD)
406 (`unOpenCode` insertVar vname x env) $
407 List.foldr bindFloatingLetMemo bodyOC bindingLFSByMemo
410 { annotatedCodeFloatingLets = FloatingLets passingFLS
411 , annotatedCodeFreeVars =
412 Set.delete (unVar vname) $
413 annotatedCodeFreeVars bodyCD
414 `Set.difference` Set.fromList (floatingLetVarname <$> bindingFLS)
417 (body (lookupVarLetInserter vname))
420 , Syn.LetRecable Int code
422 Syn.Letable (LetInserter code)
424 let_ expR body = LetInserter $ do
429 let (bindingFLS, passingFLS) =
431 (\fl -> Set.member (unVar vname) (floatingLetFreeVars fl))
432 (unFloatingLets (annotatedCodeFloatingLets bodyCD))
433 in let bindingLFSByMemo = groupBy ((==) `on` floatingLetMemo) bindingFLS
437 Syn.let_ (unOpenCode expOC env) $ \x ->
438 (`unOpenCode` (insertVar vname x env)) $
439 List.foldr bindFloatingLetMemo bodyOC bindingLFSByMemo
443 { annotatedCodeFloatingLets = FloatingLets passingFLS
444 , annotatedCodeFreeVars =
445 Set.delete (unVar vname) $
446 annotatedCodeFreeVars bodyCD
447 `Set.difference` Set.fromList (floatingLetVarname <$> bindingFLS)
451 (body (lookupVarLetInserter vname))
453 bindLet :: Syn.Letable code => FloatingLet code -> OpenCode code a -> OpenCode code a
454 bindLet fl2@FloatingLet{..} c =
455 traceShow ("bindLet", fl2) $
456 case floatingLetBoundCode of
457 BoundCodeOpenCode oc -> OpenCode $ \env ->
458 Syn.let_ (unOpenCode oc env) $ \x ->
460 -- traceShow ("bindLet", floatingLetVarName) $
461 insertVar floatingLetVarName x env
462 _ -> error "bindLet is always called for evaluated bindings, without latent bound exp"
464 -- instance Syn.LetRecable idx (LetInserter sem) where
465 -- letRec _idx f body =
466 -- let self idx = LetInserter (\loc ->
467 -- --trace ("letRec "<>show loc) $
468 -- unR (f self idx) (PNote "fix":loc))
471 -- mletRec :: p -> ((t1 -> LetInserter sem a) -> t1 -> LetInserter sem a) -> ((t1 -> LetInserter sem a) -> t2) -> t2
472 -- mletRec _idx f body =
473 -- let self idx = LetInserter $
474 -- --trace ("letRec "<>show loc) $
479 -- Syn.LetRecable Int sem =>
480 -- (sem a -> sem a) ->
481 -- (sem a -> sem w) ->
483 -- letR f body = Syn.letRec (1::Int)
484 -- (\self _idx -> f (self 0))
485 -- (\self -> body (self 0))
486 -- type family MemoKey (sem:: Type -> Type) where MemoKey a = Memo
488 -- | Memoizing non-recursive genLet
489 class MemoGenLetable sem where
490 withLocus :: (Locus -> sem a) -> sem a
491 genLetMemoAtMaybe :: Maybe Memo -> Maybe Locus -> sem a -> sem a
493 genLetMemo :: MemoGenLetable sem => Memo -> Locus -> sem a -> sem a
494 genLetMemo m l = genLetMemoAtMaybe (Just m) (Just l)
496 genLet :: MemoGenLetable sem => sem a -> sem a
497 genLet = genLetMemoAtMaybe Nothing Nothing
499 genLetAt :: MemoGenLetable sem => Locus -> sem a -> sem a
500 genLetAt = genLetMemoAtMaybe Nothing . Just
502 instance Syn.Letable code => MemoGenLetable (LetInserter code) where
503 withLocus body = LetInserter $ do
504 lname <- Locus <$> freshNatural
505 bodyCD <- unR (body lname)
506 let fls = annotatedCodeFloatingLets bodyCD
507 let bindingByLocusFLS = List.filter (\fl -> floatingLetLocus fl == Just lname) (unFloatingLets fls)
508 let bindingVars = foldMap (Set.singleton . floatingLetVarname) bindingByLocusFLS
509 let (bindingFLS, passingFLS) = List.partition (\fl -> not (Set.disjoint bindingVars (floatingLetFreeVars fl))) (unFloatingLets fls)
510 let bindingLFSByMemo = groupBy ((==) `on` floatingLetMemo) bindingFLS
512 traceShow (["withLocus"], ("bindingLFSByMemo", bindingLFSByMemo)) $
513 -- check_no_dup_varname (annotatedCodeFloatingLets bodyCD) $
515 { annotatedCodeOpenCode = List.foldr bindFloatingLetMemo (annotatedCodeOpenCode bodyCD) bindingLFSByMemo
516 , annotatedCodeFloatingLets = FloatingLets passingFLS
517 , annotatedCodeFreeVars = annotatedCodeFreeVars bodyCD `Set.difference` Set.fromList (floatingLetVarname <$> bindingFLS)
519 genLetMemoAtMaybe keyMaybe mlname body = LetInserter $ traceShow (["genLetMemoAtMaybe"]) $ do
521 -- mkey <- runIdentity <$> unR key
523 traceShow ("genLetMemoAtMaybe", ("vname", vname), ("key", keyMaybe)) $
525 let fvs = Set.insert (unVar vname) (annotatedCodeFreeVars bodyCD)
526 -- if the bodyression to let-bind has itself let-bindings,
527 -- they are straightened out
528 -- The new binding is added at the end; it may depend on
529 -- the bindings in evl (as is the case for the nested genLet)
532 { annotatedCodeOpenCode = lookupVar vname
533 , annotatedCodeFloatingLets =
535 unFloatingLets (annotatedCodeFloatingLets bodyCD)
537 { floatingLetLocus = mlname
538 , floatingLetMemo = MaybeMemo keyMaybe
539 , floatingLetVarName = vname
540 , floatingLetBoundCode = BoundCodeOpenCode (annotatedCodeOpenCode bodyCD)
541 , floatingLetFreeVars = fvs
544 , annotatedCodeFreeVars = fvs
547 -- Bind the variables in order, preserving the dependency.
548 -- Bind only one variable within each group, substituting the others
549 bindFloatingLetMemo :: Syn.Letable code => [FloatingLet code] -> OpenCode code a -> OpenCode code a
550 bindFloatingLetMemo gr oc =
551 traceShow (["withLocus", "bindFloatingLetMemo"]) $
552 case assertSameLocuses gr of
553 [] -> error "bindFloatingLetMemo: empty group"
554 [fl] -> bindLet fl oc
555 fl@FloatingLet{floatingLetVarName = vName} : fls ->
556 bindLet fl $ OpenCode $ \env ->
557 let defCode = unOpenCode (lookupVar vName) env
558 in let ext_equ env' fl2 =
559 reBind2 (memKey fl) defCode fl2
561 in unOpenCode oc $ List.foldl' ext_equ env fls
563 memKey fl@FloatingLet{floatingLetBoundCode = BoundCodeOpenCode{}} = floatingLetMemo fl
564 memKey fl = error $ "group pust be canonical: " <> show fl
566 assertSameLocuses :: [FloatingLet code] -> [FloatingLet code]
567 assertSameLocuses fls
568 | Set.size (foldMap (Set.singleton . floatingLetLocus) fls) <= 1 = traceShow ("assertSameLocuses", fls) fls
569 | otherwise = error "assertSameLocuses"
571 -- | Especially for 'Locus', all bindings have the same type.
572 -- In any event, 'Locus' plus the 'Memo' key witness for the bindings' type.
573 reBind2 :: MaybeMemo -> code a -> FloatingLet sem -> EnvBind code
575 | k == floatingLetMemo fl =
576 traceShow (["reBind2"], ("k", k), ("fl", fl)) $
577 EnvBind (Var (floatingLetVarname fl), c)
578 reBind2 k _ fl = error $ "reBind2: locus/memo mismatch" <> show (("k", k), ("fl", fl))
581 genLetAt :: LetInserter code a -> LetInserter code a
582 genLetAt = LetInserter $
586 -- TODO: Here genlet is a version of genlet l em e described earlier, for the case of all memo keys being distinct.
587 -- TODO: newtype LocusRec = Locus
589 genLetM = LetInserter $ \loc ->
594 -- | Unlike withLocus, we now have to evaluate expressions that
595 -- may be present in virtual bindings.
596 -- The rule: within an equivalence class, we evaluate only
597 -- the bexp of its representative (the first member of the group)
598 -- That evaluation may create more virtual bindings, which are to be merged
600 -- Pick vlbindings for the given locus and convert them to
602 -- * normal* equivalence classes.
604 -- Return the list of normal equivalence classes and the
605 -- remaining bindings (for different loci).
606 -- An equivalence class is called normal if its representative
607 -- (the first binding in the group) has the BoundCodeOpenCode as the bound
608 -- expression (that is, it is determined which future-stage expression to bind).
609 -- If a group is not normal, that is, its representative has a not
610 -- yet determined bound expression, we have to determine it --
611 -- which creates more bindings to normalize (some of which could be
612 -- members of existing groups -- but never replace the existing
613 -- representative -- we always preserve the order!)
615 -- Keeping the correct order and maintain dependency is actually
616 -- very difficult. When evaluating the expression bound to var v,
617 -- we obtain a code value with vlbindings. Some of them mention v
618 -- (and so should be put into the same group as v, but _after_ it),
619 -- some are new and so should be put in a group _before_ v because
620 -- the v binding may depend on them.
621 -- It seems simpler to just forget about the order between groups
622 -- and dependencies and generate one big letrec with mutually dependent clauses.
624 -- | @('groupBy' eq xs)@: partition a list @xs@
625 -- into a list of equivalence classes quotiented by the @eq@ function
627 -- The order of the groups follows the order in the input list;
628 -- within each group, the elements occur in the same order they
629 -- do in the input list.
630 groupBy :: (a -> a -> Bool) -> [a] -> [[a]]
633 go acc [] = List.reverse acc
634 go acc (x : xs) = go ((x : grp) : acc) rest
636 (grp, rest) = List.partition (eq x) xs
638 normalizeGroup :: Locus -> FloatingLets code -> MT.State Natural ([FloatingLets code], FloatingLets code)
639 normalizeGroup lname vl = do
640 let (bindingFLS, passingFLS) = List.partition (\FloatingLet{..} -> floatingLetLocus == Just lname) (unFloatingLets vl)
641 let bindingLFSByMemo = groupBy ((==) `on` floatingLetMemo) bindingFLS
642 -- Try to find an abnormal group
643 let (normalGroups, abnormalGroups) =
644 let abnomality_check = \case
645 FloatingLet{floatingLetBoundCode = BoundCodeLetInserter{}} : _ -> True
647 in List.break abnomality_check bindingLFSByMemo
648 -- traceShow (["normalizeGroup"], ("lname",lname), ("bindingLFSByMemo", FloatingLets <$> bindingLFSByMemo), ("normalGroups", FloatingLets <$> normalGroups), ("abnormalGroups", FloatingLets <$> abnormalGroups), ("passingFLS", FloatingLets passingFLS)) $
649 case abnormalGroups of
650 -- all groups are normal
653 traceShow (["normalizeGroup", "return"], ("lname", lname), ("normalGroups", FloatingLets <$> normalGroups), ("passingFLS", passingFLS)) $
654 (FloatingLets <$> normalGroups, FloatingLets passingFLS)
655 -- at least one group representative is abnormal
656 (fl0@FloatingLet{floatingLetBoundCode = BoundCodeLetInserter fl0Exp, floatingLetVarName = fl0VarName} : fls0) : grps -> do
657 fl0BodyCD <- unR fl0Exp
658 -- The group has become normal
661 { floatingLetLocus = floatingLetLocus fl0
662 , floatingLetMemo = floatingLetMemo fl0
663 , floatingLetVarName = fl0VarName
664 , floatingLetBoundCode = BoundCodeOpenCode (annotatedCodeOpenCode fl0BodyCD)
665 , -- Update the free variables, which could not be done in 'genLetMemoRec'
666 -- where fl0BodyCD was not yet available.
667 floatingLetFreeVars = floatingLetFreeVars fl0 <> annotatedCodeFreeVars fl0BodyCD
670 let groups = normalGroups <> (normalizedFL0 : grps)
672 -- let vl' = FloatingLets (List.concat groups) <> FloatingLets passingFLS <> annotatedCodeFloatingLets fl0BodyCD
673 let vl' = FloatingLets $ List.concat groups <> passingFLS <> unFloatingLets (annotatedCodeFloatingLets fl0BodyCD)
674 normalizeGroup lname vl'
675 _ -> error "normalizeGroup: groups are always non-empty"
677 -- * Class 'MemoGenLetRecable'
678 class MemoGenLetRecable sem where
679 withLocusRec :: (Locus -> sem a) -> sem a
680 genLetMemoRec :: Locus -> Memo -> sem a -> sem a
683 Syn.LetRecable Int code =>
684 MemoGenLetRecable (LetInserter code)
686 withLocusRec body = LetInserter $ do
687 lname <- Locus <$> freshNatural
688 bodyCD <- unR $ body lname
689 (bindingFLS, passingFLS) <-
690 check_no_dup_varname (annotatedCodeFloatingLets bodyCD) $
691 normalizeGroup lname (annotatedCodeFloatingLets bodyCD)
692 -- Bind the variables in order, preserving the dependency
694 traceShow (["withLocusRec", "return"], ("lname", lname), ("bindingFLS", bindingFLS), ("passingFLS", passingFLS)) $
696 { annotatedCodeOpenCode = bindFloatingLetMemoRec bindingFLS (annotatedCodeOpenCode bodyCD)
697 , annotatedCodeFloatingLets = passingFLS
698 , annotatedCodeFreeVars = annotatedCodeFreeVars bodyCD `Set.difference` foldMap (Set.fromList . (floatingLetVarname <$>) . unFloatingLets) bindingFLS
700 genLetMemoRec lname key body = LetInserter $ do
702 -- Cannot compute all the free variables yet
703 -- because body is not yet evaluated to a 'AnnotatedCode'
704 let fvs = Set.singleton (unVar vname)
706 traceShow (["genLetMemoRec"], ("key", key), ("vname", vname)) $
708 { annotatedCodeOpenCode = lookupVar vname
709 , annotatedCodeFloatingLets =
712 { floatingLetLocus = Just lname
713 , floatingLetMemo = MaybeMemo (Just key)
714 , floatingLetVarName = vname
715 , floatingLetBoundCode = BoundCodeLetInserter body
716 , floatingLetFreeVars = fvs
719 , annotatedCodeFreeVars = fvs
722 -- | Create mutually-recursive letrec bindings.
723 -- All variables are bound at the same time.
724 -- The binding expression is taken from the group representative.
725 -- It has to be 'BoundCodeOpenCode': all groups assumed to be normal.
726 bindFloatingLetMemoRec ::
727 Syn.LetRecable Int code =>
728 [FloatingLets code] ->
731 bindFloatingLetMemoRec [] c = c
732 bindFloatingLetMemoRec bindingFLS c =
733 traceShow (["bindFloatingLetMemoRec", "OpenCode"], ("bindingFLS", bindingFLS)) $
735 traceShow (["bindFloatingLetMemoRec", "Syn.letRec"], ("bindingFLS", bindingFLS), ("env", env)) $
739 traceShow (["bindFloatingLetMemoRec", "Syn.letRec", "binds"], ("idx", idx)) $
740 ( traceShow (["bindFloatingLetMemoRec", "Syn.letRec", "binds", "List.!!"], ("len", len), ("idx", idx), ("env", env)) $
741 unOpenCode (tobindOC List.!! idx)
743 ( traceShow (["bindFloatingLetMemoRec", "Syn.letRec", "binds", "bind_all"], ("idx", idx), ("env", env)) $
748 traceShow (["bindFloatingLetMemoRec", "Syn.letRec", "end"], ("env", env)) $
749 unOpenCode c (bind_all self env)
752 len = List.length bindingFLS
753 -- (label,key) of group representative
754 lk (fl@FloatingLet{floatingLetBoundCode = BoundCodeOpenCode{}} : _) = floatingLetMemo fl
755 lk _ = error "groups must be non-empty and canonical"
756 bind_group :: code a -> FloatingLets code -> [EnvBind code]
757 -- Create bindings to bind all identifiers in a group
758 bind_group ec (FloatingLets grp) =
759 traceShow (["bindFloatingLetMemoRec", "bind_group"], ("grp", grp)) $
760 List.map (reBind2 (lk grp) ec) (assertSameLocuses grp)
762 traceShow (["bindFloatingLetMemoRec", "bind_all"], ("bindingFLS", bindingFLS), ("env", env)) $
764 List.zipWith (\grp i -> bind_group (self i) grp) bindingFLS [0 :: Int .. pred len] <> [env]
766 traceShow (["bindFloatingLetMemoRec", "tobindOC"], ("bindingFLS", bindingFLS)) $
769 -- TODO: avoid unwrapping
770 FloatingLets (fl@FloatingLet{floatingLetBoundCode = BoundCodeOpenCode oc} : _) ->
771 traceShow (["bindFloatingLetMemoRec", "tobindOC", "map"], fl) $
773 _ -> error "tobindOC"
778 genLetLocus :: Syn.Letable code => (Locus -> LetInserter code a) -> LetInserter code a
779 genLetLocus body = LetInserter $ do
780 lname <- Locus <$> freshNatural
782 traceShow ("genLetLocus", ("lname", lname)) $
784 let (bindingFLS, passingFLS) =
785 List.partition (\fl -> floatingLetLocus fl == Just lname)
786 (unFloatingLets (annotatedCodeFloatingLets bodyCD))
787 -- Bind the variables in order, preserving the dependency
788 --traceShow ("genLetLocus", (bindingFLS, passingFLS)) $
790 check_no_dup_varname (annotatedCodeFloatingLets bodyCD) $
791 AnnotatedCode{ annotatedCodeOpenCode = List.foldr bindLet (annotatedCodeOpenCode bodyCD) bindingFLS
792 , annotatedCodeFloatingLets = FloatingLets passingFLS
793 , annotatedCodeFreeVars = annotatedCodeFreeVars bodyCD `Set.difference` Set.fromList (floatingLetVarname <$> bindingFLS)
795 -- In MetaOCaml, let(rec) is actually inserted either at the place
796 -- of the explicit let locus,
797 -- or at the binding that dominates all free variables of the bound expression,
798 -- whichever has the narrowest scope.
799 genLetAtMaybe :: Maybe Locus -> LetInserter code a -> LetInserter code a
800 genLetAtMaybe mlname body = LetInserter $ do
803 traceShow ("genLet", ("vname", vname)) $
805 -- if the expression to let-bind has itself let-bindings,
806 -- they are straightened out
807 -- The new binding is added at the end; it may depend on
808 -- the bindings coming before (as is the case for the nested genLet)
810 traceShow (["genLet", "bodyCD"], ("vname", vname), ("bodyCDFreeVars", (annotatedCodeFreeVars bodyCD))) $
812 { annotatedCodeOpenCode = traceShow (["genLet", "lookupVar"], ("vname", vname)) $ lookupVar vname
813 , annotatedCodeFloatingLets = FloatingLets $
814 --(\vls -> traceShow (["genLet", "bindings"], vls) vls) $
815 unFloatingLets (annotatedCodeFloatingLets bodyCD) <>
817 { floatingLetLocus = mlname
818 , floatingLetMemo = MaybeMemo (Just 0)
819 , floatingLetVarName = vname
820 , floatingLetBoundCode = BoundCodeOpenCode (annotatedCodeOpenCode bodyCD)
821 , floatingLetFreeVars = Set.insert (unVar vname) (annotatedCodeFreeVars bodyCD)
824 , annotatedCodeFreeVars = Set.insert (unVar vname) $ annotatedCodeFreeVars bodyCD
826 genLetAt :: Locus -> LetInserter code a -> LetInserter code a
827 genLetAt = genLetAtMaybe . Just
829 genLet :: LetInserter code a -> LetInserter code a
830 genLet = genLetAtMaybe Nothing