remove IsQty interface
This commit is contained in:
parent
5fdba77d04
commit
ba2818a865
24 changed files with 729 additions and 889 deletions
|
@ -1,91 +1,144 @@
|
|||
||| 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
|
||||
module Quox.Syntax.Qty
|
||||
|
||||
import Quox.Pretty
|
||||
import Quox.Name
|
||||
import public Quox.Decidable
|
||||
import Quox.Decidable
|
||||
import Data.DPair
|
||||
import Derive.Prelude
|
||||
|
||||
%default total
|
||||
%language ElabReflection
|
||||
|
||||
|
||||
||| 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
|
||||
public export
|
||||
data Qty = Zero | One | Any
|
||||
%name Qty.Qty pi, rh
|
||||
|
||||
%runElab derive "Qty" [Eq, Ord, Show]
|
||||
|
||||
|
||||
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"
|
||||
public export
|
||||
prettySuffix : Pretty.HasEnv m => Qty -> m (Doc HL)
|
||||
prettySuffix = prettyM
|
||||
|
||||
public export
|
||||
interface Eq q => IsQty q where
|
||||
zero, one, any : q
|
||||
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
|
||||
|
||||
(+), (*) : q -> q -> q
|
||||
lub : q -> q -> Maybe q
|
||||
|
||||
||| true if bindings of this quantity will be erased
|
||||
||| and must not be runtime relevant
|
||||
IsZero : Pred q
|
||||
isZero : Dec1 IsZero
|
||||
zeroIsZero : IsZero zero
|
||||
||| 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
|
||||
|
||||
||| true if bindings of this quantity can be used any number of times.
|
||||
||| this is needed for natural elimination
|
||||
IsAny : Pred q
|
||||
isAny : Dec1 IsAny
|
||||
anyIsAny : IsAny 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
|
||||
|
||||
||| ``p `Compat` q`` if it is ok for a binding of quantity `q` to be used
|
||||
||| exactly `p` times. e.g. ``1 `Compat` 1``, ``1 `Compat` ω``.
|
||||
||| if ``π `lub` ρ`` exists, then both `π` and `ρ` must be compatible with it
|
||||
Compat : Rel q
|
||||
compat : Dec2 Compat
|
||||
||| "π ≤ ρ"
|
||||
|||
|
||||
||| 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
|
||||
|
||||
||| true if it is ok for this quantity to appear for the
|
||||
||| subject of a typing judgement [@qtt, §2.3].
|
||||
IsSubj : Pred q
|
||||
isSubj : Dec1 IsSubj
|
||||
zeroIsSubj : forall pi. IsZero pi -> IsSubj pi
|
||||
oneIsSubj : IsSubj one
|
||||
timesSubj : forall pi, rh. IsSubj pi -> IsSubj rh -> IsSubj (pi * rh)
|
||||
|
||||
||| true if it is ok for a global definition to have this
|
||||
||| quantity. so not exact usage counts, maybe.
|
||||
IsGlobal : Pred q
|
||||
isGlobal : Dec1 IsGlobal
|
||||
zeroIsGlobal : forall pi. IsZero pi -> IsGlobal pi
|
||||
anyIsGlobal : forall pi. IsAny pi -> IsGlobal pi
|
||||
||| "π ∧ ρ"
|
||||
|||
|
||||
||| returns some quantity τ where π ≤ τ and ρ ≤ τ, if one exists.
|
||||
public export
|
||||
lub : Qty -> Qty -> Maybe Qty
|
||||
lub p q =
|
||||
if p == Any || q == Any then Just Any
|
||||
else if p == q then Just p
|
||||
else Nothing
|
||||
|
||||
||| prints in a form that can be a suffix of "case"
|
||||
prettySuffix : Pretty.HasEnv m => q -> m (Doc HL)
|
||||
|
||||
||| 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
|
||||
0 SQty : (q : Type) -> IsQty q => Type
|
||||
SQty q = Subset q IsSubj
|
||||
SQty : Type
|
||||
SQty = Subset Qty $ So . isSubj
|
||||
|
||||
public export %inline
|
||||
szero : IsQty q => SQty q
|
||||
szero = Element zero $ zeroIsSubj zeroIsZero
|
||||
|
||||
public export %inline
|
||||
sone : IsQty q => SQty q
|
||||
sone = Element one oneIsSubj
|
||||
szero, sone : SQty
|
||||
szero = Element Zero Oh
|
||||
sone = Element One Oh
|
||||
|
||||
||| "σ ⨴ π"
|
||||
|||
|
||||
||| ``sg `subjMult` pi`` is equal to `pi` if it is zero, otherwise it
|
||||
||| is equal to `sg`.
|
||||
public export %inline
|
||||
subjMult : IsQty q => SQty q -> q -> SQty q
|
||||
subjMult sg pi = case isZero pi of
|
||||
Yes y => Element pi $ zeroIsSubj y
|
||||
No _ => sg
|
||||
||| σ ⨭ π is 0 if either of σ or π are, otherwise it is σ.
|
||||
public export
|
||||
subjMult : SQty -> Qty -> SQty
|
||||
subjMult _ Zero = szero
|
||||
subjMult sg _ = sg
|
||||
|
||||
|
||||
||| 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
|
||||
public export
|
||||
isGlobal : Qty -> Bool
|
||||
isGlobal Zero = True
|
||||
isGlobal One = False
|
||||
isGlobal Any = True
|
||||
|
||||
public export
|
||||
0 GQty : (q : Type) -> IsQty q => Type
|
||||
GQty q = Subset q IsGlobal
|
||||
GQty : Type
|
||||
GQty = Subset Qty $ So . isGlobal
|
||||
|
||||
public export
|
||||
gzero, gany : GQty
|
||||
gzero = Element Zero Oh
|
||||
gany = Element Any Oh
|
||||
|
||||
||| 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
|
||||
gzero : IsQty q => GQty q
|
||||
gzero = Element zero $ zeroIsGlobal zeroIsZero
|
||||
|
||||
public export %inline
|
||||
gany : IsQty q => GQty q
|
||||
gany = Element any $ anyIsGlobal anyIsAny
|
||||
|
||||
export %inline
|
||||
globalToSubj : IsQty q => GQty q -> SQty q
|
||||
globalToSubj q = if isYes $ isZero q.fst then szero else sone
|
||||
globalToSubj : GQty -> SQty
|
||||
globalToSubj (Element Zero _) = szero
|
||||
globalToSubj (Element Any _) = sone
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue