module Base.Types
(
Type (..), applyType, unapplyType, rootOfType
, isArrowType, arrowArity, arrowArgs, arrowBase, arrowUnapply
, IsType (..), typeConstrs
, qualifyType, unqualifyType, qualifyTC
, Pred (..), qualifyPred, unqualifyPred
, PredSet, emptyPredSet, partitionPredSet, minPredSet, maxPredSet
, qualifyPredSet, unqualifyPredSet
, PredType (..), predType, unpredType, qualifyPredType, unqualifyPredType
, DataConstr (..), constrIdent, constrTypes, recLabels, recLabelTypes
, tupleData
, ClassMethod (..), methodName, methodArity, methodType
, TypeScheme (..), ExistTypeScheme (..), monoType, polyType, typeScheme
, rawType
, arrowType, unitType, predUnitType, boolType, predBoolType, charType
, intType, predIntType, floatType, predFloatType, stringType, predStringType
, listType, consType, ioType, tupleType
, numTypes, fractionalTypes
, predefTypes
) where
import qualified Data.Set.Extra as Set
import Curry.Base.Ident
import Base.Messages (internalError)
import Env.Class (ClassEnv, allSuperClasses)
data Type
= TypeConstructor QualIdent
| TypeVariable Int
| TypeConstrained [Type] Int
| TypeSkolem Int
| TypeApply Type Type
| TypeArrow Type Type
| TypeForall [Int] Type
deriving (Eq, Ord, Show)
applyType :: Type -> [Type] -> Type
applyType (TypeConstructor tc) tys
| tc == qArrowId && length tys == 2 = TypeArrow (tys !! 0) (tys !! 1)
applyType (TypeApply (TypeConstructor tc) ty) tys
| tc == qArrowId && length tys == 1 = TypeArrow ty (head tys)
applyType ty tys = foldl TypeApply ty tys
unapplyType :: Bool -> Type -> (Type, [Type])
unapplyType dflt ty = unapply ty []
where
unapply (TypeConstructor tc) tys = (TypeConstructor tc, tys)
unapply (TypeApply ty1 ty2) tys = unapply ty1 (ty2 : tys)
unapply (TypeVariable tv) tys = (TypeVariable tv, tys)
unapply (TypeArrow ty1 ty2) tys =
(TypeConstructor qArrowId, ty1 : ty2 : tys)
unapply (TypeConstrained tys tv) tys'
| dflt = unapply (head tys) tys'
| otherwise = (TypeConstrained tys tv, tys')
unapply (TypeSkolem k) tys = (TypeSkolem k, tys)
unapply (TypeForall tvs ty') tys = (TypeForall tvs ty', tys)
rootOfType :: Type -> QualIdent
rootOfType ty = case fst (unapplyType True ty) of
TypeConstructor tc -> tc
_ -> internalError $ "Base.Types.rootOfType: " ++ show ty
isArrowType :: Type -> Bool
isArrowType (TypeArrow _ _) = True
isArrowType _ = False
arrowArity :: Type -> Int
arrowArity = length. arrowArgs
arrowArgs :: Type -> [Type]
arrowArgs = fst . arrowUnapply
arrowBase :: Type -> Type
arrowBase = snd. arrowUnapply
arrowUnapply :: Type -> ([Type], Type)
arrowUnapply (TypeArrow ty1 ty2) = (ty1 : tys, ty)
where (tys, ty) = arrowUnapply ty2
arrowUnapply ty = ([], ty)
typeConstrs :: Type -> [QualIdent]
typeConstrs ty = constrs ty [] where
constrs (TypeConstructor tc) tcs = tc : tcs
constrs (TypeApply ty1 ty2) tcs = constrs ty1 (constrs ty2 tcs)
constrs (TypeVariable _) tcs = tcs
constrs (TypeConstrained _ _) tcs = tcs
constrs (TypeArrow ty1 ty2) tcs = constrs ty1 (constrs ty2 tcs)
constrs (TypeSkolem _) tcs = tcs
constrs (TypeForall _ ty') tcs = constrs ty' tcs
class IsType t where
typeVars :: t -> [Int]
typeSkolems :: t -> [Int]
instance IsType Type where
typeVars = typeVars'
typeSkolems = typeSkolems'
typeVars' :: Type -> [Int]
typeVars' ty = vars ty [] where
vars (TypeConstructor _) tvs = tvs
vars (TypeApply ty1 ty2) tvs = vars ty1 (vars ty2 tvs)
vars (TypeVariable tv) tvs = tv : tvs
vars (TypeConstrained _ _) tvs = tvs
vars (TypeArrow ty1 ty2) tvs = vars ty1 (vars ty2 tvs)
vars (TypeSkolem _) tvs = tvs
vars (TypeForall tvs' ty') tvs = filter (`notElem` tvs') (typeVars' ty') ++ tvs
typeSkolems' :: Type -> [Int]
typeSkolems' ty = skolems ty [] where
skolems (TypeConstructor _) sks = sks
skolems (TypeApply ty1 ty2) sks = skolems ty1 (skolems ty2 sks)
skolems (TypeVariable _) sks = sks
skolems (TypeConstrained _ _) sks = sks
skolems (TypeArrow ty1 ty2) sks = skolems ty1 (skolems ty2 sks)
skolems (TypeSkolem k) sks = k : sks
skolems (TypeForall _ ty') sks = skolems ty' sks
qualifyType :: ModuleIdent -> Type -> Type
qualifyType m (TypeConstructor tc) = TypeConstructor (qualifyTC m tc)
qualifyType m (TypeApply ty1 ty2) =
TypeApply (qualifyType m ty1) (qualifyType m ty2)
qualifyType _ tv@(TypeVariable _) = tv
qualifyType m (TypeConstrained tys tv) =
TypeConstrained (map (qualifyType m) tys) tv
qualifyType m (TypeArrow ty1 ty2) =
TypeArrow (qualifyType m ty1) (qualifyType m ty2)
qualifyType _ ts@(TypeSkolem _) = ts
qualifyType m (TypeForall tvs ty) = TypeForall tvs (qualifyType m ty)
unqualifyType :: ModuleIdent -> Type -> Type
unqualifyType m (TypeConstructor tc) = TypeConstructor (qualUnqualify m tc)
unqualifyType m (TypeApply ty1 ty2) =
TypeApply (unqualifyType m ty1) (unqualifyType m ty2)
unqualifyType _ tv@(TypeVariable _) = tv
unqualifyType m (TypeConstrained tys tv) =
TypeConstrained (map (unqualifyType m) tys) tv
unqualifyType m (TypeArrow ty1 ty2) =
TypeArrow (unqualifyType m ty1) (unqualifyType m ty2)
unqualifyType _ ts@(TypeSkolem _) = ts
unqualifyType m (TypeForall tvs ty) = TypeForall tvs (unqualifyType m ty)
qualifyTC :: ModuleIdent -> QualIdent -> QualIdent
qualifyTC m tc | isPrimTypeId tc = tc
| otherwise = qualQualify m tc
data Pred = Pred QualIdent Type
deriving (Eq, Show)
instance Ord Pred where
Pred qcls1 ty1 `compare` Pred qcls2 ty2 = case ty1 `compare` ty2 of
LT -> LT
EQ -> qcls1 `compare` qcls2
GT -> GT
instance IsType Pred where
typeVars (Pred _ ty) = typeVars ty
typeSkolems (Pred _ ty) = typeSkolems ty
qualifyPred :: ModuleIdent -> Pred -> Pred
qualifyPred m (Pred qcls ty) = Pred (qualQualify m qcls) (qualifyType m ty)
unqualifyPred :: ModuleIdent -> Pred -> Pred
unqualifyPred m (Pred qcls ty) =
Pred (qualUnqualify m qcls) (unqualifyType m ty)
type PredSet = Set.Set Pred
instance (IsType a, Ord a) => IsType (Set.Set a) where
typeVars = concat . Set.toList . Set.map typeVars
typeSkolems = concat . Set.toList . Set.map typeSkolems
emptyPredSet :: PredSet
emptyPredSet = Set.empty
partitionPredSet :: PredSet -> (PredSet, PredSet)
partitionPredSet = Set.partition $ \(Pred _ ty) -> isTypeVariable ty
where
isTypeVariable (TypeVariable _) = True
isTypeVariable (TypeApply ty _) = isTypeVariable ty
isTypeVariable _ = False
minPredSet :: ClassEnv -> PredSet -> PredSet
minPredSet clsEnv ps =
ps `Set.difference` Set.concatMap implied ps
where implied (Pred cls ty) = Set.fromList
[Pred cls' ty | cls' <- tail (allSuperClasses cls clsEnv)]
maxPredSet :: ClassEnv -> PredSet -> PredSet
maxPredSet clsEnv ps = Set.concatMap implied ps
where implied (Pred cls ty) = Set.fromList
[Pred cls' ty | cls' <- allSuperClasses cls clsEnv]
qualifyPredSet :: ModuleIdent -> PredSet -> PredSet
qualifyPredSet m = Set.map (qualifyPred m)
unqualifyPredSet :: ModuleIdent -> PredSet -> PredSet
unqualifyPredSet m = Set.map (unqualifyPred m)
data PredType = PredType PredSet Type
deriving (Eq, Show)
instance IsType PredType where
typeVars (PredType ps ty) = typeVars ty ++ typeVars ps
typeSkolems (PredType ps ty) = typeSkolems ty ++ typeSkolems ps
predType :: Type -> PredType
predType = PredType emptyPredSet
unpredType :: PredType -> Type
unpredType (PredType _ ty) = ty
qualifyPredType :: ModuleIdent -> PredType -> PredType
qualifyPredType m (PredType ps ty) =
PredType (qualifyPredSet m ps) (qualifyType m ty)
unqualifyPredType :: ModuleIdent -> PredType -> PredType
unqualifyPredType m (PredType ps ty) =
PredType (unqualifyPredSet m ps) (unqualifyType m ty)
data DataConstr = DataConstr Ident Int PredSet [Type]
| RecordConstr Ident Int PredSet [Ident] [Type]
deriving (Eq, Show)
constrIdent :: DataConstr -> Ident
constrIdent (DataConstr c _ _ _) = c
constrIdent (RecordConstr c _ _ _ _) = c
constrTypes :: DataConstr -> [Type]
constrTypes (DataConstr _ _ _ tys) = tys
constrTypes (RecordConstr _ _ _ _ tys) = tys
recLabels :: DataConstr -> [Ident]
recLabels (DataConstr _ _ _ _) = []
recLabels (RecordConstr _ _ _ ls _) = ls
recLabelTypes :: DataConstr -> [Type]
recLabelTypes (DataConstr _ _ _ _) = []
recLabelTypes (RecordConstr _ _ _ _ tys) = tys
tupleData :: [DataConstr]
tupleData = [DataConstr (tupleId n) 0 emptyPredSet (take n tvs) | n <- [2 ..]]
where tvs = map TypeVariable [0 ..]
data ClassMethod = ClassMethod Ident (Maybe Int) PredType
deriving (Eq, Show)
methodName :: ClassMethod -> Ident
methodName (ClassMethod f _ _) = f
methodArity :: ClassMethod -> Maybe Int
methodArity (ClassMethod _ a _) = a
methodType :: ClassMethod -> PredType
methodType (ClassMethod _ _ pty) = pty
data TypeScheme = ForAll Int PredType deriving (Eq, Show)
data ExistTypeScheme = ForAllExist Int Int PredType deriving (Eq, Show)
instance IsType TypeScheme where
typeVars (ForAll _ pty) = [tv | tv <- typeVars pty, tv < 0]
typeSkolems (ForAll _ pty) = typeSkolems pty
instance IsType ExistTypeScheme where
typeVars (ForAllExist _ _ pty) = [tv | tv <- typeVars pty, tv < 0]
typeSkolems (ForAllExist _ _ pty) = typeSkolems pty
monoType :: Type -> TypeScheme
monoType = ForAll 0 . predType
polyType :: Type -> TypeScheme
polyType = typeScheme . predType
typeScheme :: PredType -> TypeScheme
typeScheme pty = ForAll (maximum (-1 : typeVars pty) + 1) pty
rawType :: TypeScheme -> Type
rawType (ForAll _ (PredType _ ty)) = ty
primType :: QualIdent -> [Type] -> Type
primType = applyType . TypeConstructor
arrowType :: Type -> Type -> Type
arrowType ty1 ty2 = primType qArrowId [ty1, ty2]
unitType :: Type
unitType = primType qUnitId []
predUnitType :: PredType
predUnitType = predType unitType
boolType :: Type
boolType = primType qBoolId []
predBoolType :: PredType
predBoolType = predType boolType
charType :: Type
charType = primType qCharId []
intType :: Type
intType = primType qIntId []
predIntType :: PredType
predIntType = predType intType
floatType :: Type
floatType = primType qFloatId []
predFloatType :: PredType
predFloatType = predType floatType
stringType :: Type
stringType = listType charType
predStringType :: PredType
predStringType = predType stringType
listType :: Type -> Type
listType ty = primType qListId [ty]
consType :: Type -> Type
consType ty = TypeArrow ty (TypeArrow (listType ty) (listType ty))
ioType :: Type -> Type
ioType ty = primType qIOId [ty]
tupleType :: [Type] -> Type
tupleType tys = primType (qTupleId (length tys)) tys
numTypes :: [Type]
numTypes = [intType, floatType]
fractionalTypes :: [Type]
fractionalTypes = drop 1 numTypes
predefTypes :: [(Type, [DataConstr])]
predefTypes =
[ (arrowType a b, [])
, (unitType , [ DataConstr unitId 0 emptyPredSet [] ])
, (listType a , [ DataConstr nilId 0 emptyPredSet []
, DataConstr consId 0 emptyPredSet [a, listType a]
])
]
where a = TypeVariable 0
b = TypeVariable 1