packages feed

alms-0.6.0: src/AST/Type.hs

{-# LANGUAGE TypeFamilies #-}
module AST.Type (
  -- * Types
  Quant(..), Type'(..), Type, TyPat'(..), TyPat,
  -- ** Constructors
  tyApp, tyVar, tyFun, tyQu, tyMu, tyRow, tyAnti,
  tpVar, tpApp, tpRow, tpAnti,
  TyAppN(..),

  -- * Built-in types
  tyUnit, tyRowEnd, tyVariant, tyRecord, tyRowDots, tyRowMap, tyRowHole,
  tyTuple, tyUn, tyAf,
  -- ** Type construtor names
  tnUnit, tnRowEnd, tnVariant, tnRecord, tnRowDots, tnRowMap, tnRowHole,
  tnTuple, tnUn, tnAf,
  -- ** Convenience constructors
  tyArr, tyLol,
  tyAll, tyEx,
  tyRecordAdditive, tyRecordMultiplicative,

  -- * Miscellany
  dumpType
) where

import Util
import Meta.DeriveNotable
import AST.Notable
import AST.Anti
import AST.Kind
import AST.Ident
import qualified Syntax.Strings as Strings

import Prelude ()
import Data.Generics (Typeable, Data)

-- | Type quantifers
data Quant = Forall | Exists | QuantAnti Anti
  deriving (Typeable, Data, Eq, Ord)

type Type i  = Located Type' i
type TyPat i = Located TyPat' i

-- | Types are parameterized by [@i@], the type of information
--   associated with each tycon
data Type' i
  = TyApp  (QTypId i) [Type i]
  | TyVar  (TyVar i)
  | TyFun  (Type i) (Maybe (QExp i)) (Type i)
  | TyQu   Quant (TyVar i) (Type i)
  | TyMu   (TyVar i) (Type i)
  | TyRow  (Uid i) (Type i) (Type i)
  | TyAnti Anti
  deriving (Typeable, Data)

-- | Type patterns for defining type operators
data TyPat' i
  -- | type variables
  = TpVar (TyVar i) Variance
  -- | type constructor applications
  | TpApp (QTypId i) [TyPat i]
  -- | each element of a row
  | TpRow (TyVar i) Variance
  -- | antiquotes
  | TpAnti Anti
  deriving (Typeable, Data)

deriveNotable ''Type
deriveNotable ''TyPat

-- | Convenience constructors for qualified types
tyAll, tyEx :: TyVar i -> Type i -> Type i
tyAll = tyQu Forall
tyEx  = tyQu Exists

tyArr         :: Type i -> Type i -> Type i
tyArr          = tyFun <-> Nothing

tyLol         :: Type i -> Type i -> Type i
tyLol          = tyFun <-> Just maxBound

infixr 8 `tyArr`, `tyLol`

instance Show Quant where
  show Forall        = Strings.all
  show Exists        = Strings.ex
  show (QuantAnti a) = show a

---
--- Built-in types
---

-- | Names of built-in types
tnUnit, tnRowEnd, tnVariant, tnRecord, tnRowDots, tnRowMap, tnRowHole,
  tnTuple, tnUn, tnAf :: String

tnUnit         = "INTERNALS.PrimTypes.unit"
tnRowEnd       = "INTERNALS.PrimTypes.rowend"
tnVariant      = "INTERNALS.PrimTypes.variant"
tnRecord       = "INTERNALS.PrimTypes.record"
tnRowDots      = "rowdots#"
tnRowMap       = "rowmap#"
tnRowHole      = "rowhole#"
tnTuple        = "INTERNALS.PrimTypes.*"
tnUn           = "INTERNALS.PrimTypes.unlimited"
tnAf           = "INTERNALS.PrimTypes.affine"

--- Convenience constructors

-- Types

-- | Class defining variadic function 'tyAppN' for constructing
--   type constructor applications.
class TyApp' r i ⇒ TyAppN n r i | r → i where
  tyAppN ∷ n → r

instance TyApp' r i ⇒ TyAppN (Path (ModId i) (TypId i)) r i where
  tyAppN ql = tyApp' ql []

instance TyApp' r i ⇒ TyAppN (TypId i) r i where
  tyAppN l = tyApp' (J [] l) []

instance (Tag i, TyApp' r i) ⇒ TyAppN String r i where
  tyAppN s = tyApp' (qident s) []

-- | Helper class for @TyApp'@.
class TyApp' r i | r → i where
  tyApp' ∷ QTypId i → [Type i] → r

instance TyApp' (Type i) i where
  tyApp' = tyApp

instance (TyApp' r i, a ~ Type i) ⇒ TyApp' (a → r) i where
  tyApp' ql ts t = tyApp' ql (ts++[t])

tyUnit        :: Tag i => Type i
tyUnit         = tyAppN tnUnit

tyRowEnd      :: Tag i => Type i
tyRowEnd       = tyAppN tnRowEnd

tyVariant     :: Tag i => Type i -> Type i
tyVariant      = tyAppN tnVariant

tyRecord      :: Tag i => Type i -> Type i -> Type i
tyRecord       = tyAppN tnRecord

tyRowDots     :: Tag i => Type i -> Type i
tyRowDots      = tyAppN tnRowDots

tyRowMap      :: Tag i => Type i -> Type i -> Type i
tyRowMap       = tyAppN tnRowMap

tyRowHole     :: Tag i => Type i -> Type i
tyRowHole      = tyAppN tnRowHole

tyTuple       :: Tag i => Type i -> Type i -> Type i
tyTuple        = tyAppN tnTuple

tyUn          :: Tag i => Type i
tyUn           = tyAppN tnUn

tyAf          :: Tag i => Type i
tyAf           = tyAppN tnAf

tyRecordAdditive, tyRecordMultiplicative :: Tag i => Type i -> Type i
tyRecordAdditive       = tyRecord tyAf
tyRecordMultiplicative = tyRecord tyUn

---
--- Debugging
---

-- | Noisy type printer for debugging
dumpType :: Tag i => Int -> Type i -> IO ()
dumpType i0 nt0 = do
  putStr (replicate i0 ' ')
  noIndent i0 nt0
  where
  noIndent i nt@(N _ t0) =
    case t0 of
      TyApp n ps -> do
        putStrLn $ show n ++ " {"
        mapM_ (dumpType (i + 2)) ps
        putStrLn (replicate i ' ' ++ "}")
      TyFun dom mq cod -> do
        putStrLn $ case mq of
          Just q  -> "-[" ++ dumpQExp q ++ "]> {"
          Nothing -> "-> {"
        dumpType (i + 2) dom
        dumpType (i + 2) cod
        putStrLn (replicate i ' ' ++ "}")
      TyVar tv -> print tv
      TyQu u a t -> do
        print $ show u ++ " " ++ show a ++ ". {"
        dumpType (i + 2) t
        putStrLn (replicate i ' ' ++ "}")
      TyMu a t -> do
        print $ "mu " ++ show a ++ ". {"
        dumpType (i + 2) t
        putStrLn (replicate i ' ' ++ "}")
      TyRow _ _ _ -> do
        putStr "ro"
        dumpRow (i + 2) 'w' nt
      TyAnti a -> do
        print a
  --
  dumpRow i c (N _ (TyRow n t1 t2)) = do
    let lab = show n
    putStr (c:' ':lab++": ")
    noIndent (i + length lab + 4) t1
    putStr (replicate i ' ')
    dumpRow i '|' t2
  dumpRow i c t = do
    putStr (c:" ")
    noIndent (i + 2) t
  --
  dumpQExp (N _ q0) = case q0 of
    QeLit ql       → show ql
    QeVar tv       → show tv
    QeJoin qe1 qe2 → dumpQExp qe1 ++ ',' : dumpQExp qe2
    QeAnti _       → "ANTI"