alms-0.6.0: src/AST/Kind.hs
module AST.Kind (
-- * Qualifiers and variance
QLit(..), Variance(..),
-- ** Qualifier expressions
QExp, QExp'(..), qeLit, qeVar, qeAnti, qeJoin,
-- ** Qualifier operations
(\-\), elimQLit, qLitSigil,
-- ** Variance operations
isQVariance,
-- * Modules
) where
import Util
import Meta.DeriveNotable
import Data.Lattice
import AST.Anti
import AST.Notable
import {-# SOURCE #-} AST.Ident
import qualified Syntax.Strings as Strings
import Prelude ()
import Data.Generics (Typeable, Data)
---
--- QUALIFIERS, VARIANCES
---
{- | Usage qualifier literals
A
|
U
-}
data QLit
-- | unlimited
= Qu
-- | affine
| Qa
deriving (Eq, Ord, Bounded, Typeable, Data)
type QExp i = Located QExp' i
-- | Usage qualifier expressions
data QExp' i
-- | qualifier literal
= QeLit QLit
-- | type variable
| QeVar (TyVar i)
-- | join
| QeJoin (QExp i) (QExp i)
-- | antiquote
| QeAnti Anti
deriving (Typeable, Data)
deriveNotable ''QExp
{- |
Type constructor variance forms a seven point lattice, which keeps track
of both polarity and parameters that should be treated as qualifiers.
In particular, given a unary type constructor T with variance +, T S <:
T U when S <: U; but if T has variance Q+, then T S <: T U when
|S| ≤ |U|, where |⋅| gives the qualifier of a type.
=
/|\
/ | \
/ | \
+ Q= -
| / \ |
|/ \ |
Q+ Q-
\ /
\ /
\ /
0
-}
data Variance
-- | 0
= Omnivariant
-- | Q+
| QCovariant
-- | Q-
| QContravariant
-- | Q=
| QInvariant
-- | +
| Covariant
-- | -
| Contravariant
-- | =
| Invariant
deriving (Eq, Ord, Typeable, Data)
---
--- Order instances
---
instance Lattice QLit where
Qa ⊔ _ = Qa
Qu ⊔ ql = ql
Qu ⊓ _ = Qu
Qa ⊓ ql = ql
Qa ⊑ Qu = False
_ ⊑ _ = True
-- | Variances are a four point lattice with 'Invariant' on top and
-- 'Omnivariant' on the bottom
instance Bounded Variance where
minBound = Omnivariant
maxBound = Invariant
instance Lattice Variance where
Omnivariant ⊔ v2 = v2
v1 ⊔ Omnivariant = v1
QCovariant ⊔ Covariant = Covariant
Covariant ⊔ QCovariant = Covariant
QContravariant ⊔ Contravariant = Contravariant
Contravariant ⊔ QContravariant = Contravariant
v1 ⊔ v2
| v1 == v2 = v1
| isQVariance v1 && isQVariance v2
= QInvariant
| otherwise = Invariant
--
Invariant ⊓ v2 = v2
v1 ⊓ Invariant = v1
QCovariant ⊓ Covariant = QCovariant
Covariant ⊓ QCovariant = QCovariant
QInvariant ⊓ Covariant = QCovariant
Covariant ⊓ QInvariant = QCovariant
QContravariant ⊓ Contravariant = QContravariant
Contravariant ⊓ QContravariant = QContravariant
QInvariant ⊓ Contravariant = QContravariant
Contravariant ⊓ QInvariant = QContravariant
QInvariant ⊓ QCovariant = QCovariant
QCovariant ⊓ QInvariant = QCovariant
QInvariant ⊓ QContravariant = QContravariant
QContravariant ⊓ QInvariant = QContravariant
v1 ⊓ v2
| v1 == v2 = v1
| otherwise = Omnivariant
--
Omnivariant ⊑ _ = True
QCovariant ⊑ Covariant = True
QContravariant ⊑ Contravariant = True
QCovariant ⊑ QInvariant = True
QContravariant ⊑ QInvariant = True
_ ⊑ Invariant = True
v1 ⊑ v2 = v1 == v2
instance Bounded (QExp' i) where
minBound = QeLit Qu
maxBound = QeLit Qa
---
--- Other instances
---
instance Show QLit where
showsPrec _ Qu = ('U':)
showsPrec _ Qa = ('A':)
instance Show Variance where
show Invariant = Strings.invariant
show Covariant = Strings.covariant
show Contravariant = Strings.contravariant
show Omnivariant = Strings.omnivariant
show QInvariant = Strings.qinvariant
show QCovariant = Strings.qcovariant
show QContravariant = Strings.qcontravariant
instance Monoid QLit where
mempty = minBound
mappend = (⊔)
instance Monoid Variance where
mempty = minBound
mappend = (⊔)
-- | Variances work like abstract sign arithmetic, where:
-- Omnivariant = { 0 }
-- Covariant = ℤ₊ = { 0, 1, 2, ... }
-- Contravariant = ℤ₋ = { ..., -2, -1, 0 }
-- Invariant = ℤ
-- QCovariant = 2ℤ₊ = { 0, 2, 4, ... }
-- QContravariant = 2ℤ₋ = { ..., -4, -2, 0 }
-- QInvariant = 2ℤ = { ..., -4, -2, 0, 2, 4, ... }
--- In this view, addition gives the join for the variance lattice,
-- and multiplication gives the variance of composing type constructors
-- of the given variances (more or less).
instance Num Variance where
(+) = (⊔)
--
Omnivariant * _ = Omnivariant
Covariant * v2 = v2
v1 * Covariant = v1
Contravariant * v2 = negate v2
v1 * Contravariant = negate v1
QCovariant * v2 = v2 ⊓ QInvariant
v1 * QCovariant = v1 ⊓ QInvariant
QContravariant * v2 = negate v2 ⊓ QInvariant
v1 * QContravariant = negate v1 ⊓ QInvariant
QInvariant * _ = QInvariant
_ * QInvariant = QInvariant
_ * _ = Invariant
--
abs Omnivariant = Omnivariant
abs v | isQVariance v = QCovariant
| otherwise = Covariant
--
signum QCovariant = Covariant
signum QContravariant = Contravariant
signum QInvariant = Invariant
signum v = v
--
negate Covariant = Contravariant
negate Contravariant = Covariant
negate QCovariant = QContravariant
negate QContravariant = QCovariant
negate v = v
--
fromInteger i
| i > 0 = if even i then QCovariant else Covariant
| i < 0 = if even i then QContravariant else Contravariant
| otherwise = Omnivariant
---
--- Operations
---
--
-- Qualifiers
--
-- | @a \-\ b@ is the least @c@ such that
-- @a ⊑ b ⊔ c@. (This is sort of dual to a pseudocomplement.)
(\-\) ∷ QLit → QLit → QLit
Qa \-\ Qu = Qu
_ \-\ _ = Qu
elimQLit ∷ a → a → QLit → a
elimQLit u _ Qu = u
elimQLit _ a Qa = a
qLitSigil ∷ QLit → String
qLitSigil Qu = Strings.unlimited
qLitSigil Qa = Strings.affine
--
-- Variances
--
isQVariance ∷ Variance → Bool
isQVariance QCovariant = True
isQVariance QContravariant = True
isQVariance QInvariant = True
isQVariance _ = False