alms-0.6.0: src/Type/ArrowAnnotations.hs
-- | Rules for interpreting arrow qualifier annotations.
module Type.ArrowAnnotations (
-- * Between internal and external qualifier expressions
qInterpret, qRepresent,
-- * Arrow annotation rules
ImpArrRule(..), CurrentImpArrRule, CurrentImpArrPrintingRule,
) where
import Util
import Meta.Quasi
import qualified AST
import Type.Internal
import Prelude ()
import qualified Data.Set as S
type R = AST.Renamed
-- | The rule for parsing arrows
#ifdef ANNOTATION_RULE
type CurrentImpArrRule = ANNOTATION_RULE
#else
type CurrentImpArrRule = Rule3
#endif
-- | The rule for printing arrows
#ifdef ANNOTATION_PRINTING_RULE
type CurrentImpArrPrintingRule = ANNOTATION_PRINTING_RULE
#else
type CurrentImpArrPrintingRule = CurrentImpArrRule
#endif
-- | Interpret an explicit external qualifier as an internal one
qInterpret ∷ (Ord tv, Monad m) ⇒
(AST.TyVar R → m tv) →
AST.QExp R → m (QExp tv)
qInterpret resolve = loop where
loop [qeQ| $qlit:ql |] = return (qlitexp ql)
loop [qeQ| `$tv |] = qvarexp `liftM` resolve tv
loop [qeQ| $qe1 ⋁ $qe2 |] = (⊔) `liftM` loop qe1 `ap` loop qe2
loop [qeQ| $anti:a |] = $(AST.antifail)
-- | Represent an internal qualifier as an explicit external one
qRepresent ∷ (tv → AST.TyVar R) →
QExp tv → AST.QExp R
qRepresent _ QeA = [qeQ|+! A |]
qRepresent rename (QeU tvs)
| S.null tvs = [qeQ|+! U |]
| otherwise =
foldr1 AST.qeJoin (AST.qeVar . rename <$> S.toList tvs)
-- | Interface to rules for implicit annotation of arrows
class ImpArrRule rule where
-- | The initial labeling state
iaeInit ∷ rule tv
-- | Update the state to the left of an arrow
iaeLeft ∷ rule tv → rule tv
-- | Update the state to the right of an arrow with the given
-- qualifier
iaeRight ∷ Ord tv ⇒ rule tv → QExpV tv → Type tv → rule tv
-- | The implied qualifier at a particular point
iaeImplied ∷ rule tv → QExpV tv
-- | Interpret the given implicit qualifier into an explicit qualifier
-- at the given point
iaeInterpret ∷ (Ord tv, Monad m) ⇒
(AST.TyVar R → m (TyVar tv)) →
rule tv → Maybe (AST.QExp R) → m (QExpV tv)
-- | Represent the given explicit qualifier as an implicit one
iaeRepresent ∷ Eq tv ⇒
(TyVar tv → AST.TyVar R) →
rule tv → QExpV tv → Maybe (AST.QExp R)
-- | Update the state under the given variance
iaeUnder ∷ rule tv → Variance → rule tv
--
iaeLeft _ = iaeInit
iaeRight iae _ _ = iae
iaeImplied _ = minBound
iaeInterpret resolve iae
= maybe (return (iaeImplied iae)) (qInterpret resolve)
iaeRepresent rename iae actual
| actual == iaeImplied iae = Nothing
| otherwise = Just (qRepresent rename actual)
iaeUnder _ _ = iaeInit
-- | Print all arrow annotations explicitly
data Rule0 tv = Rule0
instance ImpArrRule Rule0 where
iaeInit = Rule0
iaeRepresent rename _ actual = Just (qRepresent rename actual)
-- | Annotation ‘U’ is implicit for unlabeled arrows.
data Rule1 tv = Rule1
instance ImpArrRule Rule1 where
iaeInit = Rule1
newtype Rule2 tv = Rule2 { unRule2 ∷ QExpV tv }
-- | Implicit annotation is lub of qualifiers of prior curried
-- arguments. Explicit annotations have no effect on subsequent
-- arrows.
instance ImpArrRule Rule2 where
iaeInit = Rule2 minBound
iaeRight iae _ t = Rule2 (unRule2 iae ⊔ qualifier t)
iaeImplied = unRule2
-- | Like 'Rule2', but explicit annotations reset the qualifier to
-- themselves for subsequent arrows.
newtype Rule3 tv = Rule3 { unRule3 ∷ QExpV tv }
instance ImpArrRule Rule3 where
iaeInit = Rule3 minBound
iaeRight _ actual t = Rule3 (actual ⊔ qualifier t)
iaeImplied = unRule3
-- | Like 'Rule3', but we arrow the implicit qualifer into covariant
-- type constructors.
newtype Rule4 tv = Rule4 { unRule4 ∷ QExpV tv }
instance ImpArrRule Rule4 where
iaeInit = Rule4 minBound
iaeRight _ actual t = Rule4 (actual ⊔ qualifier t)
iaeImplied = unRule4
iaeUnder iae Covariant = iae
iaeUnder _ _ = iaeInit
-- | Like 'Rule4', but we carry the implicit quantifier into ALL type
-- constructors and only use it when we arrive at an arrow in a
-- positive position wrt the surrounding arrow.
data Rule5 tv
= Rule5 {
unRule5 ∷ !(QExpV tv),
r4Var ∷ !Variance
}
instance ImpArrRule Rule5 where
iaeInit = Rule5 minBound 1
iaeRight _ actual t = Rule5 (actual ⊔ qualifier t) 1
iaeImplied iae
| r4Var iae == 1 = unRule5 iae
| otherwise = minBound
iaeUnder iae var = Rule5 (unRule5 iae) (var * r4Var iae)