2023-04-01 13:16:43 -04:00
|
|
|
|
||| quantities count how many times a bound variable is used [@nuttin; @qtt].
|
|
|
|
|
|||
|
|
|
|
|
||| i tried grtt [@grtt] for a bit but i think it was more complex than
|
|
|
|
|
||| it's worth in a language that has other stuff going on too
|
2021-07-20 16:05:19 -04:00
|
|
|
|
module Quox.Syntax.Qty
|
|
|
|
|
|
|
|
|
|
import Quox.Pretty
|
2023-04-01 13:16:43 -04:00
|
|
|
|
import Quox.Decidable
|
2023-01-08 14:44:25 -05:00
|
|
|
|
import Data.DPair
|
2023-04-01 13:16:43 -04:00
|
|
|
|
import Derive.Prelude
|
2021-07-20 16:05:19 -04:00
|
|
|
|
|
2022-05-02 16:38:37 -04:00
|
|
|
|
%default total
|
2023-04-01 13:16:43 -04:00
|
|
|
|
%language ElabReflection
|
2021-07-20 16:05:19 -04:00
|
|
|
|
|
|
|
|
|
|
2023-04-01 13:16:43 -04:00
|
|
|
|
||| the possibilities we care about are:
|
|
|
|
|
|||
|
|
|
|
|
||| - 0: a variable is used only at compile time, not run time
|
|
|
|
|
||| - 1: a variable is used exactly once at run time
|
|
|
|
|
||| - ω (or #): don't care. an ω variable *can* also be used 0/1 time
|
2021-07-20 16:05:19 -04:00
|
|
|
|
public export
|
2023-04-01 13:16:43 -04:00
|
|
|
|
data Qty = Zero | One | Any
|
|
|
|
|
%name Qty.Qty pi, rh
|
|
|
|
|
|
|
|
|
|
%runElab derive "Qty" [Eq, Ord, Show]
|
|
|
|
|
|
2023-03-18 18:27:27 -04:00
|
|
|
|
|
2023-04-01 13:16:43 -04:00
|
|
|
|
export
|
|
|
|
|
PrettyHL Qty where
|
|
|
|
|
prettyM pi = hl Qty <$>
|
|
|
|
|
case pi of
|
|
|
|
|
Zero => pure "0"
|
|
|
|
|
One => pure "1"
|
|
|
|
|
Any => ifUnicode "ω" "#"
|
|
|
|
|
|
|
|
|
|
||| prints in a form that can be a suffix of "case"
|
2022-04-27 16:57:56 -04:00
|
|
|
|
public export
|
2023-04-01 13:16:43 -04:00
|
|
|
|
prettySuffix : Pretty.HasEnv m => Qty -> m (Doc HL)
|
|
|
|
|
prettySuffix = prettyM
|
2022-04-27 16:57:56 -04:00
|
|
|
|
|
2023-04-01 13:16:43 -04:00
|
|
|
|
public export
|
|
|
|
|
DecEq Qty where
|
|
|
|
|
decEq Zero Zero = Yes Refl
|
|
|
|
|
decEq Zero One = No $ \case _ impossible
|
|
|
|
|
decEq Zero Any = No $ \case _ impossible
|
|
|
|
|
decEq One Zero = No $ \case _ impossible
|
|
|
|
|
decEq One One = Yes Refl
|
|
|
|
|
decEq One Any = No $ \case _ impossible
|
|
|
|
|
decEq Any Zero = No $ \case _ impossible
|
|
|
|
|
decEq Any One = No $ \case _ impossible
|
|
|
|
|
decEq Any Any = Yes Refl
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||| e.g. if in the expression `(s, t)`, the variable `x` is
|
|
|
|
|
||| used π times in `s` and ρ times in `t`, then it's used
|
|
|
|
|
||| (π + ρ) times in the whole expression
|
|
|
|
|
public export
|
|
|
|
|
(+) : Qty -> Qty -> Qty
|
|
|
|
|
Zero + rh = rh
|
|
|
|
|
pi + Zero = pi
|
|
|
|
|
_ + _ = Any
|
|
|
|
|
|
|
|
|
|
||| e.g. if a function `f` uses its argument π times,
|
|
|
|
|
||| and `f x` occurs in a σ context, then `x` is used `πσ` times overall
|
|
|
|
|
public export
|
|
|
|
|
(*) : Qty -> Qty -> Qty
|
|
|
|
|
Zero * _ = Zero
|
|
|
|
|
_ * Zero = Zero
|
|
|
|
|
One * rh = rh
|
|
|
|
|
pi * One = pi
|
|
|
|
|
Any * Any = Any
|
|
|
|
|
|
|
|
|
|
||| "π ≤ ρ"
|
|
|
|
|
|||
|
|
|
|
|
||| if a variable is bound with quantity ρ, then it can be used with a total
|
|
|
|
|
||| quantity π as long as π ≤ ρ. for example, an ω variable can be used any
|
|
|
|
|
||| number of times, so π ≤ ω for any π.
|
|
|
|
|
public export
|
|
|
|
|
compat : Qty -> Qty -> Bool
|
|
|
|
|
compat pi Any = True
|
|
|
|
|
compat pi rh = pi == rh
|
|
|
|
|
|
|
|
|
|
|
2023-04-17 15:41:10 -04:00
|
|
|
|
||| "π ∨ ρ"
|
2023-04-01 13:16:43 -04:00
|
|
|
|
|||
|
|
|
|
|
||| returns some quantity τ where π ≤ τ and ρ ≤ τ, if one exists.
|
|
|
|
|
public export
|
|
|
|
|
lub : Qty -> Qty -> Maybe Qty
|
2023-04-17 15:41:10 -04:00
|
|
|
|
lub p q = Just $ if p == q then p else Any
|
2023-04-01 13:16:43 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||| to maintain subject reduction, only 0 or 1 can occur
|
|
|
|
|
||| for the subject of a typing judgment. see @qtt, §2.3 for more detail
|
|
|
|
|
public export
|
|
|
|
|
isSubj : Qty -> Bool
|
|
|
|
|
isSubj Zero = True
|
|
|
|
|
isSubj One = True
|
|
|
|
|
isSubj Any = False
|
|
|
|
|
|
|
|
|
|
public export
|
|
|
|
|
SQty : Type
|
|
|
|
|
SQty = Subset Qty $ So . isSubj
|
2023-01-08 14:44:25 -05:00
|
|
|
|
|
|
|
|
|
public export %inline
|
2023-04-01 13:16:43 -04:00
|
|
|
|
szero, sone : SQty
|
|
|
|
|
szero = Element Zero Oh
|
|
|
|
|
sone = Element One Oh
|
2022-08-22 04:07:46 -04:00
|
|
|
|
|
2023-02-19 11:42:11 -05:00
|
|
|
|
||| "σ ⨴ π"
|
|
|
|
|
|||
|
2023-04-01 13:16:43 -04:00
|
|
|
|
||| σ ⨭ π is 0 if either of σ or π are, otherwise it is σ.
|
|
|
|
|
public export
|
|
|
|
|
subjMult : SQty -> Qty -> SQty
|
|
|
|
|
subjMult _ Zero = szero
|
|
|
|
|
subjMult sg _ = sg
|
2023-02-19 11:42:11 -05:00
|
|
|
|
|
|
|
|
|
|
2023-04-01 13:16:43 -04:00
|
|
|
|
||| it doesn't make much sense for a top level declaration to have a
|
|
|
|
|
||| quantity of 1, so the only distinction is whether it is present
|
|
|
|
|
||| at runtime at all or not
|
2022-04-27 16:57:56 -04:00
|
|
|
|
public export
|
2023-04-01 13:16:43 -04:00
|
|
|
|
isGlobal : Qty -> Bool
|
|
|
|
|
isGlobal Zero = True
|
|
|
|
|
isGlobal One = False
|
|
|
|
|
isGlobal Any = True
|
2023-01-08 14:44:25 -05:00
|
|
|
|
|
2023-04-01 13:16:43 -04:00
|
|
|
|
public export
|
|
|
|
|
GQty : Type
|
|
|
|
|
GQty = Subset Qty $ So . isGlobal
|
2023-03-13 14:33:09 -04:00
|
|
|
|
|
2023-04-01 13:16:43 -04:00
|
|
|
|
public export
|
|
|
|
|
gzero, gany : GQty
|
|
|
|
|
gzero = Element Zero Oh
|
|
|
|
|
gany = Element Any Oh
|
2023-04-01 10:01:53 -04:00
|
|
|
|
|
2023-04-01 13:16:43 -04:00
|
|
|
|
||| when checking a definition, a 0 definition is checked at 0,
|
|
|
|
|
||| but an ω definition is checked at 1 since ω isn't a subject quantity
|
|
|
|
|
public export %inline
|
|
|
|
|
globalToSubj : GQty -> SQty
|
|
|
|
|
globalToSubj (Element Zero _) = szero
|
|
|
|
|
globalToSubj (Element Any _) = sone
|