@@ -653,76 +653,61 @@ dischargeResultToTerm (DischargeConstant val) = Constant () val
653653dischargeResultToTerm (DischargeNonConstant term) = term
654654
655655{-| Convert a 'CekValue' into a 'Term' by replacing all bound variables with the terms
656- they're bound to (which themselves have to be obtained by recursively discharging values). -}
656+ they're bound to (which themselves have to be obtained by recursively discharging values).
657+
658+ The @global@ parameter threads a cumulative shift through the traversal: when a value looked
659+ up from an environment is discharged, its own free variables must be shifted by the number of
660+ binders that were between the reference site and the environment boundary. Instead of doing a
661+ separate post-pass ('shiftTermBy'), we fuse the shifting into the discharge by passing @global@
662+ down through 'goValue'. -}
657663dischargeCekValue :: forall uni fun ann . CekValue uni fun ann -> DischargeResult uni fun
658664dischargeCekValue (VCon val) = DischargeConstant val
659- dischargeCekValue value0 = DischargeNonConstant $ goValue value0
665+ dischargeCekValue value0 = DischargeNonConstant $ goValue 0 value0
660666 where
661- goValue :: CekValue uni fun ann -> NTerm uni fun ()
662- goValue = \ case
667+ goValue :: Word64 -> CekValue uni fun ann -> NTerm uni fun ()
668+ goValue ! global = \ case
663669 VCon val -> Constant () val
664- VDelay body env -> Delay () $ goValEnv env 0 body
670+ VDelay body env -> Delay () $ goValEnv env global 0 body
665671 VLamAbs (NamedDeBruijn n _ix) body env ->
666672 -- The index on the binder is meaningless, we put @0@ by convention, see 'Binder'.
667- LamAbs () (NamedDeBruijn n deBruijnInitIndex) $ goValEnv env 1 body
673+ LamAbs () (NamedDeBruijn n deBruijnInitIndex) $ goValEnv env global 1 body
668674 -- We only return a discharged builtin application when (a) it's being returned by the
669675 -- machine, or (b) it's needed for an error message.
670676 -- @term@ is fully discharged, so we can return it directly without any further discharging.
671677 VBuiltin _ term _ -> term
672- VConstr ind args -> Constr () ind . map goValue $ argStackToList args
678+ VConstr ind args -> Constr () ind . map ( goValue global) $ argStackToList args
673679
674680 -- Instantiate all the free variables of a term by looking them up in an environment.
675681 -- Mutually recursive with @goValue@.
676- goValEnv :: CekValEnv uni fun ann -> Word64 -> NTerm uni fun ann -> NTerm uni fun ()
682+ goValEnv :: CekValEnv uni fun ann -> Word64 -> Word64 -> NTerm uni fun ann -> NTerm uni fun ()
677683 goValEnv env = go
678684 where
679- -- @shift @ is just a counter that measures how many lambda-abstractions we have descended
680- -- into so far.
681- go :: Word64 -> NTerm uni fun ann -> NTerm uni fun ()
682- go ! shift = \ case
683- LamAbs _ name body -> LamAbs () name $ go (shift + 1 ) body
685+ -- @global @ is the accumulated shift from outer discharge contexts.
686+ -- @shift@ counts how many lambda-abstractions we have descended into so far.
687+ go :: Word64 -> Word64 -> NTerm uni fun ann -> NTerm uni fun ()
688+ go ! global ! shift = \ case
689+ LamAbs _ name body -> LamAbs () name $ go global (shift + 1 ) body
684690 Var _ named@ (NamedDeBruijn _ (coerce -> idx)) ->
685691 if shift >= idx
686692 -- the index n is less-than-or-equal than the number of lambdas we have descended
687693 -- this means that n points to a bound variable, so we don't discharge it.
688694 then Var () named
689695 else
690696 maybe
691- -- var is free, leave it alone
692- (Var () named)
693- -- var is in the env, discharge its value and shift free vars
694- (shiftTermBy shift . goValue )
697+ -- var is free and not in the env, shift it
698+ (Var () (shiftNamedDeBruijn (global + shift) named) )
699+ -- var is in the env, discharge its value with the accumulated shift
700+ (goValue (global + shift) )
695701 -- index relative to (as seen from the point of view of) the environment
696702 (Env. indexOne env $ idx - shift)
697- Apply _ fun arg -> Apply () (go shift fun) $ go shift arg
698- Delay _ term -> Delay () $ go shift term
699- Force _ term -> Force () $ go shift term
703+ Apply _ fun arg -> Apply () (go global shift fun) $ go global shift arg
704+ Delay _ term -> Delay () $ go global shift term
705+ Force _ term -> Force () $ go global shift term
700706 Constant _ val -> Constant () val
701707 Builtin _ fun -> Builtin () fun
702708 Error _ -> Error ()
703- Constr _ ind args -> Constr () ind $ map (go shift) args
704- Case _ scrut alts -> Case () (go shift scrut) $ fmap (go shift) alts
705-
706- {-| Shift all free variables in a term by the given amount.
707- A variable is free if its index is greater than the current binding depth. -}
708- shiftTermBy :: Word64 -> NTerm uni fun () -> NTerm uni fun ()
709- shiftTermBy 0 term = term -- Optimization: no-op when shift is 0
710- shiftTermBy shiftAmount term = go 0 term
711- where
712- go :: Word64 -> NTerm uni fun () -> NTerm uni fun ()
713- go ! depth = \ case
714- Var ann (NamedDeBruijn n (coerce -> idx))
715- | idx <= depth -> Var ann (NamedDeBruijn n (coerce idx)) -- Bound: unchanged
716- | otherwise -> Var ann (NamedDeBruijn n (coerce (idx + shiftAmount))) -- Free: shift
717- LamAbs ann name body -> LamAbs ann name $ go (depth + 1 ) body
718- Apply ann fun arg -> Apply ann (go depth fun) (go depth arg)
719- Delay ann t -> Delay ann $ go depth t
720- Force ann t -> Force ann $ go depth t
721- Constant ann val -> Constant ann val
722- Builtin ann fun -> Builtin ann fun
723- Error ann -> Error ann
724- Constr ann ind args -> Constr ann ind $ map (go depth) args
725- Case ann scrut alts -> Case ann (go depth scrut) $ fmap (go depth) alts
709+ Constr _ ind args -> Constr () ind $ map (go global shift) args
710+ Case _ scrut alts -> Case () (go global shift scrut) $ fmap (go global shift) alts
726711
727712instance (PrettyUni uni , Pretty fun ) => PrettyBy PrettyConfigPlc (CekValue uni fun ann ) where
728713 prettyBy cfg = prettyBy cfg . dischargeResultToTerm . dischargeCekValue
0 commit comments