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