packages feed

alms-0.6.0: src/Type/TyVar.hs

module Type.TyVar (
  -- * Type variable observations
  Tv(..), Kind(..), Flavor(..),
  tvFlavorIs, tvKindIs, uglyTvName,
  -- * Miscellany
  varianceToKind,
  -- * Free type variables
  Ftv(..), VarMap,
  FtvTree(..), foldFtvTree,
) where

import Util
import qualified AST
import Syntax.PprClass
import Type.Internal

import Prelude ()
import Data.Generics (Typeable, Data)
import qualified Data.Map as M
import qualified Data.Set as S

---
--- TYPE VARIABLES
---

-- | Internal kinds for type variables
data Kind
  -- | The kind of normal types
  = KdType
  -- | The kind of qualifier variables
  | KdQual
  deriving (Eq, Typeable, Data)

instance Ppr Kind where
  ppr KdType = char '*'
  ppr KdQual = char 'Q'
instance Show Kind where showsPrec = showFromPpr

-- | Get the kind associated with type variables that appear at a
--   particular variance.
varianceToKind ∷ Variance → Kind
varianceToKind var = if isQVariance var then KdQual else KdType

-- | Flavors of type variables
data Flavor
  -- | unification variables
  = Universal
  -- | existential skolems
  | Existential
  -- | universal skolems
  | Skolem
  deriving (Eq, Typeable, Data)

instance Ppr Flavor where ppr = char . flavorSigil
instance Show Flavor where showsPrec = showFromPpr

-- | Type variable observations
class (Ftv tv tv, Show tv, Ppr tv) ⇒ Tv tv where
  -- | The unique identity of a type variable
  tvUniqueID    ∷ tv → Int
  -- | The internal kind of a type variable
  tvKind        ∷ tv → Kind
  -- | The internal flavor of a type variable
  tvFlavor      ∷ tv → Flavor
  -- | Possibly a qualifier bound
  tvQual        ∷ tv → Maybe QLit
  -- | A description
  tvDescr       ∷ tv → Doc
  -- | Read the contents of a type variable (not pure)
  unsafeReadTV  ∷ tv → Maybe (Type tv)

instance Tv Empty where
  tvUniqueID    = elimEmpty
  tvKind        = elimEmpty
  tvFlavor      = elimEmpty
  tvQual        = elimEmpty
  tvDescr       = elimEmpty
  unsafeReadTV  = elimEmpty

instance Ftv Empty Empty where ftvTree = elimEmpty
instance Ppr Empty       where ppr = elimEmpty

instance Tv Int where
  tvUniqueID    = id
  tvKind _      = KdType
  tvFlavor _    = Skolem
  tvQual _      = Nothing
  tvDescr       = ppr
  unsafeReadTV  = const Nothing

instance Ftv Int Int where ftvTree = FTSingle

-- | Check the flavor of a type variable
tvFlavorIs ∷ Tv tv ⇒ Flavor → tv → Bool
tvFlavorIs flavor v = tvFlavor v == flavor

-- | Check the kind of a type variable
tvKindIs ∷ Tv tv ⇒ Kind → tv → Bool
tvKindIs kind v = tvKind v == kind

-- | When all else fails, we can print a type variable like this
uglyTvName ∷ Tv tv ⇒ tv → String
uglyTvName tv = flavorSigil (tvFlavor tv) : (AST.tvalphabet !! tvUniqueID tv)

-- | A character denoting a flavor
flavorSigil ∷ Flavor → Char
flavorSigil Universal   = '_'
flavorSigil Existential = '#'
flavorSigil Skolem      = '$'

---
--- FREE TYPE VARIABLES
---

{-
  We're going to construct a framework for generic functions to compute
  the free type variables of a type.  It may seem a bit over-engineered,
  but it turns out to be handy, The idea is to write a generic function
  that builds an 'FtvTree', which contains all the free type variables
  in the relevant piece of syntax, along with variance and recursive
  guard information.
-}

-- | A tree of free type variables, with variance and recursive guard
--   information
data FtvTree v
  -- | A single free type variable
  = FTSingle v
  -- | Updates the incoming variance to give the variance in
  --   the subtree
  | FTVariance VarianceEndo (FtvTree v)
  -- | Indicates that the subtree is guarded by a type constructor
  --   that allows recursion
  | FTGuard (FtvTree v)
  -- | A forest of 'FtvTree's
  | FTBranch [FtvTree v]
  deriving (Functor, Show)

-- | Type for providing a 'Show' instance for @Variance -> Variance@
-- functions which allows deriving 'Show' for 'FtvTree'.
newtype VarianceEndo
  = VarianceEndo { applyVarianceEndo ∷ Variance → Variance }

instance Show VarianceEndo where
  show ve = show (applyVarianceEndo ve 1)

instance Monoid (FtvTree v) where
  mempty      = FTBranch []
  mappend a b = FTBranch [a, b]
  mconcat     = FTBranch

-- | A fold for 'FtvTree's. It's necessary to specify how to
--   add a free type variable and its variance to the result, and the
--   initial result.  Note that this fold gives no information about
--   the shape of the tree, but it uses the tree structure to determine
--   the variance of each type variable.
foldFtvTree ∷ (v → Variance → Bool → r → r) → r → FtvTree v → r
foldFtvTree fsingle = loop Covariant False where
  loop var gua acc tree = case tree of
    FTSingle v      → fsingle v var gua acc
    FTVariance vf t → loop (applyVarianceEndo vf var) gua acc t
    FTGuard t       → loop var True acc t
    FTBranch ts     → foldr (flip (loop var gua)) acc ts

-- | Map from variables to variances
type VarMap v = M.Map v Variance

class Ord tv ⇒ Ftv a tv | a → tv where
  -- | To compute the 'FtvTree' for a piece of syntax.  Because
  --   everything is parametric in the representation of ftvs, it needs
  --   to be told how to dereference an apparently free type variable.
  --   The dereferencing function should return @Nothing@ if the type
  --   variable is actually free, and @Just τ@ if a type @τ@ has been
  --   substituted for it.
  --
  --   This is the only method that doesn't have a default
  --   implementation, so it must be defined explicitly.
  ftvTree  ∷ a → FtvTree tv
  -- | To fold over the free type variables in a piece of syntax.
  ftvFold  ∷ (tv → Variance → Bool → r → r) → r → a → r
  -- | To get a map from free type variables to their variances.
  ftvV     ∷ a → VarMap tv
  -- | To get a map from free type variables to their guardedness
  ftvG     ∷ a → M.Map tv Bool
  -- | To get a map from free type variables to a list of all their
  --   occurrences' variances.
  ftvSet   ∷ a → S.Set tv
  -- | To get a list of the free type variables in a type (with no repeats).
  ftvList  ∷ a → [tv]
  --
  --
  ftvFold fsingle zero a
                 = foldFtvTree fsingle zero $ ftvTree a
  ftvV           = ftvFold (const <$$> M.insertWith (+)) M.empty
  ftvG           = ftvFold (const <$> M.insertWith (&&)) M.empty
  ftvSet         = ftvFold (\v _ _ → S.insert v) S.empty
  ftvList        = S.toAscList . ftvSet

instance Ord tv ⇒ Ftv (Type tv) tv where
  ftvTree = foldType
              (mkQuF (\_ _ → id))
              (mkBvF (\_ _ _ → mempty))
              FTSingle
              (\tc trees → FTBranch
                 [ FTVariance (VarianceEndo (* var)) $
                     if guarded then FTGuard tree else tree
                 | tree    ← trees
                 | var     ← tcArity tc
                 | guarded ← tcGuards tc ])
              (\_ σ1 σ2 → FTBranch [FTGuard σ1, σ2])
              (mkMuF (\_ → id))

instance Ord tv ⇒ Ftv (QExp tv) tv where
  ftvTree QeA      = FTBranch []
  ftvTree (QeU αs) = FTBranch (FTSingle <$> S.toList αs)
  ftvSet QeA       = S.empty
  ftvSet (QeU αs)  = αs

instance Ftv a tv ⇒ Ftv [a] tv where
  ftvTree = foldMap ftvTree

instance Ftv a tv ⇒ Ftv (M.Map k a) tv where
  ftvTree = ftvTree . M.elems

instance (Ftv a tv, Ftv b tv) ⇒ Ftv (a, b) tv where
  ftvTree (a, b) = ftvTree a `mappend` ftvTree b

instance (Ftv a tv, Ftv b tv, Ftv c tv) ⇒ Ftv (a, b, c) tv where
  ftvTree (a, b, c) = mconcat [ftvTree a, ftvTree b, ftvTree c]

instance (Ftv a tv, Ftv b tv, Ftv c tv, Ftv d tv) ⇒ Ftv (a, b, c, d) tv where
  ftvTree (a, b, c, d) = mconcat [ftvTree a, ftvTree b, ftvTree c, ftvTree d]

instance Ftv a tv ⇒ Ftv (Maybe a) tv where
  ftvTree = maybe mempty ftvTree

instance (Ftv a tv, Ftv b tv) ⇒ Ftv (Either a b) tv where
  ftvTree = either ftvTree ftvTree