packages feed

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)