2013-07-03 12:35:51 +00:00
|
|
|
module Type.Type where
|
|
|
|
|
2013-07-08 14:47:44 +00:00
|
|
|
import qualified Data.List as List
|
2013-07-03 12:35:51 +00:00
|
|
|
import qualified Data.Map as Map
|
|
|
|
import qualified Data.UnionFind.IO as UF
|
2013-07-19 15:48:41 +00:00
|
|
|
import Type.PrettyPrint
|
2013-07-08 14:47:44 +00:00
|
|
|
import Text.PrettyPrint as P
|
2013-07-03 12:35:51 +00:00
|
|
|
import System.IO.Unsafe
|
2013-07-08 14:47:44 +00:00
|
|
|
import Control.Applicative ((<$>),(<*>))
|
|
|
|
import Control.Monad.State
|
|
|
|
import Data.Traversable (traverse)
|
2013-07-19 17:17:51 +00:00
|
|
|
import SourceSyntax.Helpers (isTuple)
|
2013-07-21 04:08:08 +00:00
|
|
|
import qualified SourceSyntax.Type as Src
|
2013-07-03 12:35:51 +00:00
|
|
|
|
|
|
|
data Term1 a
|
|
|
|
= App1 a a
|
|
|
|
| Fun1 a a
|
|
|
|
| Var1 a
|
|
|
|
| EmptyRecord1
|
|
|
|
| Record1 (Map.Map String [a]) a
|
|
|
|
deriving Show
|
|
|
|
|
|
|
|
data TermN a
|
|
|
|
= VarN a
|
|
|
|
| TermN (Term1 (TermN a))
|
2013-07-08 14:47:44 +00:00
|
|
|
deriving Show
|
2013-07-03 12:35:51 +00:00
|
|
|
|
|
|
|
record fs rec = TermN (Record1 fs rec)
|
|
|
|
|
2013-07-21 04:08:08 +00:00
|
|
|
type Type = TermN Variable
|
|
|
|
type Variable = UF.Point Descriptor
|
|
|
|
|
2013-07-03 12:35:51 +00:00
|
|
|
type SchemeName = String
|
|
|
|
type TypeName = String
|
|
|
|
|
|
|
|
data Constraint a b
|
|
|
|
= CTrue
|
2013-07-19 15:48:41 +00:00
|
|
|
| CSaveEnv
|
2013-07-03 12:35:51 +00:00
|
|
|
| CEqual a a
|
|
|
|
| CAnd [Constraint a b]
|
|
|
|
| CLet [Scheme a b] (Constraint a b)
|
|
|
|
| CInstance SchemeName a
|
|
|
|
deriving Show
|
|
|
|
|
|
|
|
data Scheme a b = Scheme {
|
|
|
|
rigidQuantifiers :: [b],
|
|
|
|
flexibleQuantifiers :: [b],
|
|
|
|
constraint :: Constraint a b,
|
2013-07-08 14:47:44 +00:00
|
|
|
header :: Map.Map String a
|
2013-07-03 12:35:51 +00:00
|
|
|
} deriving Show
|
|
|
|
|
2013-07-21 04:08:08 +00:00
|
|
|
type TypeConstraint = Constraint Type Variable
|
|
|
|
type TypeScheme = Scheme Type Variable
|
|
|
|
|
2013-07-03 17:51:38 +00:00
|
|
|
monoscheme headers = Scheme [] [] CTrue headers
|
|
|
|
|
2013-07-03 12:35:51 +00:00
|
|
|
data Descriptor = Descriptor {
|
|
|
|
structure :: Maybe (Term1 Variable),
|
|
|
|
rank :: Int,
|
|
|
|
flex :: Flex,
|
2013-07-07 10:52:48 +00:00
|
|
|
name :: Maybe TypeName,
|
2013-07-09 19:52:05 +00:00
|
|
|
copy :: Maybe Variable,
|
2013-07-07 10:52:48 +00:00
|
|
|
mark :: Int
|
2013-07-08 14:47:44 +00:00
|
|
|
} deriving Show
|
2013-07-03 12:35:51 +00:00
|
|
|
|
2013-07-07 10:52:48 +00:00
|
|
|
noRank = -1
|
|
|
|
outermostRank = 0 :: Int
|
|
|
|
|
2013-07-09 19:52:05 +00:00
|
|
|
noMark = 0
|
|
|
|
initialMark = 1
|
|
|
|
|
2013-07-24 23:24:16 +00:00
|
|
|
data Flex = Rigid | Flexible | Constant | IsIn SuperType
|
|
|
|
deriving (Show, Eq)
|
|
|
|
|
|
|
|
data SuperType = Number | Comparable | Appendable
|
2013-07-07 10:52:48 +00:00
|
|
|
deriving (Show, Eq)
|
2013-07-03 12:35:51 +00:00
|
|
|
|
|
|
|
infixl 8 /\
|
|
|
|
|
|
|
|
(/\) :: Constraint a b -> Constraint a b -> Constraint a b
|
2013-07-19 15:48:41 +00:00
|
|
|
a /\ CTrue = a
|
|
|
|
CTrue /\ b = b
|
2013-07-03 12:35:51 +00:00
|
|
|
a /\ b = CAnd [a,b]
|
|
|
|
|
|
|
|
(===) :: Type -> Type -> TypeConstraint
|
|
|
|
(===) = CEqual
|
|
|
|
|
|
|
|
(<?) :: SchemeName -> Type -> TypeConstraint
|
|
|
|
x <? t = CInstance x t
|
|
|
|
|
|
|
|
infixr 9 ==>
|
|
|
|
(==>) :: Type -> Type -> Type
|
|
|
|
a ==> b = TermN (Fun1 a b)
|
|
|
|
|
2013-07-17 17:26:42 +00:00
|
|
|
f <| a = TermN (App1 f a)
|
|
|
|
|
2013-07-24 23:24:16 +00:00
|
|
|
number = namedVar (IsIn Number) "number"
|
2013-07-17 17:26:42 +00:00
|
|
|
|
2013-07-19 15:48:41 +00:00
|
|
|
namedVar flex name = UF.fresh $ Descriptor {
|
2013-07-03 12:35:51 +00:00
|
|
|
structure = Nothing,
|
|
|
|
rank = noRank,
|
2013-07-19 15:48:41 +00:00
|
|
|
flex = flex,
|
2013-07-07 10:52:48 +00:00
|
|
|
name = Just name,
|
2013-07-09 19:52:05 +00:00
|
|
|
copy = Nothing,
|
|
|
|
mark = noMark
|
2013-07-03 12:35:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
flexibleVar = UF.fresh $ Descriptor {
|
|
|
|
structure = Nothing,
|
|
|
|
rank = noRank,
|
|
|
|
flex = Flexible,
|
2013-07-07 10:52:48 +00:00
|
|
|
name = Nothing,
|
2013-07-09 19:52:05 +00:00
|
|
|
copy = Nothing,
|
|
|
|
mark = noMark
|
2013-07-03 12:35:51 +00:00
|
|
|
}
|
|
|
|
|
2013-07-03 17:51:38 +00:00
|
|
|
rigidVar = UF.fresh $ Descriptor {
|
|
|
|
structure = Nothing,
|
|
|
|
rank = noRank,
|
|
|
|
flex = Rigid,
|
2013-07-07 10:52:48 +00:00
|
|
|
name = Nothing,
|
2013-07-09 19:52:05 +00:00
|
|
|
copy = Nothing,
|
|
|
|
mark = noMark
|
2013-07-03 17:51:38 +00:00
|
|
|
}
|
|
|
|
|
2013-07-03 12:35:51 +00:00
|
|
|
-- ex qs constraint == exists qs. constraint
|
|
|
|
ex :: [Variable] -> TypeConstraint -> TypeConstraint
|
|
|
|
ex fqs constraint = CLet [Scheme [] fqs constraint Map.empty] CTrue
|
|
|
|
|
|
|
|
-- fl qs constraint == forall qs. constraint
|
|
|
|
fl :: [Variable] -> TypeConstraint -> TypeConstraint
|
|
|
|
fl rqs constraint = CLet [Scheme rqs [] constraint Map.empty] CTrue
|
|
|
|
|
|
|
|
exists :: (Type -> IO TypeConstraint) -> IO TypeConstraint
|
|
|
|
exists f = do
|
|
|
|
v <- flexibleVar
|
|
|
|
ex [v] <$> f (VarN v)
|
|
|
|
|
2013-07-17 17:26:42 +00:00
|
|
|
|
2013-07-03 12:35:51 +00:00
|
|
|
instance Show a => Show (UF.Point a) where
|
|
|
|
show point = unsafePerformIO $ fmap show (UF.descriptor point)
|
|
|
|
|
2013-07-08 14:47:44 +00:00
|
|
|
|
2013-07-19 15:48:41 +00:00
|
|
|
instance PrettyType a => PrettyType (UF.Point a) where
|
|
|
|
pretty when point = unsafePerformIO $ fmap (pretty when) (UF.descriptor point)
|
|
|
|
|
|
|
|
|
|
|
|
instance PrettyType a => PrettyType (Term1 a) where
|
|
|
|
pretty when term =
|
|
|
|
let prty = pretty Never in
|
2013-07-08 14:47:44 +00:00
|
|
|
case term of
|
2013-07-19 17:17:51 +00:00
|
|
|
App1 f x | P.render px == "_List" -> P.brackets (pretty Never x)
|
|
|
|
| otherwise -> parensIf needed (px <+> pretty App x)
|
2013-07-09 19:59:58 +00:00
|
|
|
where
|
2013-07-19 17:17:51 +00:00
|
|
|
px = prty f
|
2013-07-19 15:48:41 +00:00
|
|
|
needed = case when of
|
|
|
|
App -> True
|
|
|
|
_ -> False
|
|
|
|
|
|
|
|
Fun1 arg body ->
|
|
|
|
parensIf needed (pretty Fn arg <+> P.text "->" <+> prty body)
|
|
|
|
where
|
|
|
|
needed = case when of
|
|
|
|
Never -> False
|
|
|
|
_ -> True
|
|
|
|
|
|
|
|
Var1 x -> prty x
|
|
|
|
|
2013-07-08 14:47:44 +00:00
|
|
|
EmptyRecord1 -> P.braces P.empty
|
2013-07-19 15:48:41 +00:00
|
|
|
|
2013-07-08 14:47:44 +00:00
|
|
|
Record1 fields ext ->
|
2013-07-19 15:48:41 +00:00
|
|
|
P.braces (prty ext <+> P.text "|" <+> commaSep prettyFields)
|
2013-07-08 14:47:44 +00:00
|
|
|
where
|
2013-07-19 15:48:41 +00:00
|
|
|
mkPretty f t = P.text f <+> P.text ":" <+> prty t
|
2013-07-08 14:47:44 +00:00
|
|
|
prettyFields = concatMap (\(f,ts) -> map (mkPretty f) ts) (Map.toList fields)
|
|
|
|
|
2013-07-19 15:48:41 +00:00
|
|
|
|
|
|
|
instance PrettyType a => PrettyType (TermN a) where
|
|
|
|
pretty when term =
|
2013-07-08 14:47:44 +00:00
|
|
|
case term of
|
2013-07-19 15:48:41 +00:00
|
|
|
VarN x -> pretty when x
|
|
|
|
TermN t1 -> pretty when t1
|
2013-07-08 14:47:44 +00:00
|
|
|
|
2013-07-19 15:48:41 +00:00
|
|
|
|
|
|
|
instance PrettyType Descriptor where
|
|
|
|
pretty when desc =
|
2013-07-08 14:47:44 +00:00
|
|
|
case (structure desc, name desc) of
|
2013-07-19 15:48:41 +00:00
|
|
|
(Just term, _) -> pretty when term
|
2013-07-19 17:17:51 +00:00
|
|
|
(_, Just name) -> if not (isTuple name) then P.text name else
|
|
|
|
P.parens . P.text $ replicate (read (drop 6 name) - 1) ','
|
2013-07-08 14:47:44 +00:00
|
|
|
_ -> P.text "?"
|
|
|
|
|
2013-07-19 15:48:41 +00:00
|
|
|
|
|
|
|
instance (PrettyType a, PrettyType b) => PrettyType (Constraint a b) where
|
|
|
|
pretty _ constraint =
|
|
|
|
let prty = pretty Never in
|
2013-07-08 14:47:44 +00:00
|
|
|
case constraint of
|
|
|
|
CTrue -> P.text "True"
|
2013-07-19 15:48:41 +00:00
|
|
|
CSaveEnv -> P.text "SaveTheEnvironment!!!"
|
|
|
|
CEqual a b -> prty a <+> P.text "=" <+> prty b
|
2013-07-08 14:47:44 +00:00
|
|
|
CAnd [] -> P.text "True"
|
|
|
|
|
2013-07-11 21:30:18 +00:00
|
|
|
CAnd cs ->
|
2013-07-19 15:48:41 +00:00
|
|
|
P.parens . P.sep $ P.punctuate (P.text " and") (map (pretty Never) cs)
|
2013-07-08 14:47:44 +00:00
|
|
|
|
|
|
|
CLet [Scheme [] fqs constraint header] CTrue | Map.null header ->
|
2013-07-19 15:48:41 +00:00
|
|
|
P.sep [ binder, pretty Never c ]
|
2013-07-08 14:47:44 +00:00
|
|
|
where
|
2013-07-11 21:30:18 +00:00
|
|
|
mergeExists vs c =
|
|
|
|
case c of
|
|
|
|
CLet [Scheme [] fqs' c' _] CTrue -> mergeExists (vs ++ fqs') c'
|
|
|
|
_ -> (vs, c)
|
|
|
|
|
|
|
|
(fqs', c) = mergeExists fqs constraint
|
|
|
|
|
|
|
|
binder = if null fqs' then P.empty else
|
2013-07-19 15:48:41 +00:00
|
|
|
P.text "\x2203" <+> P.hsep (map (pretty Never) fqs') <> P.text "."
|
2013-07-08 14:47:44 +00:00
|
|
|
|
|
|
|
CLet schemes constraint ->
|
2013-07-19 15:48:41 +00:00
|
|
|
P.fsep [ P.hang (P.text "let") 4 (P.brackets . commaSep $ map (pretty Never) schemes)
|
|
|
|
, P.text "in", pretty Never constraint ]
|
2013-07-08 14:47:44 +00:00
|
|
|
|
|
|
|
CInstance name tipe ->
|
2013-07-19 15:48:41 +00:00
|
|
|
P.text name <+> P.text "<" <+> prty tipe
|
2013-07-08 14:47:44 +00:00
|
|
|
|
2013-07-19 15:48:41 +00:00
|
|
|
instance (PrettyType a, PrettyType b) => PrettyType (Scheme a b) where
|
|
|
|
pretty _ (Scheme rqs fqs constraint headers) =
|
2013-07-11 21:30:18 +00:00
|
|
|
P.sep [ forall, cs, headers' ]
|
2013-07-08 14:47:44 +00:00
|
|
|
where
|
2013-07-19 15:48:41 +00:00
|
|
|
prty = pretty Never
|
|
|
|
|
2013-07-11 21:30:18 +00:00
|
|
|
forall = if null rqs && null fqs then P.empty else
|
2013-07-19 15:48:41 +00:00
|
|
|
P.text "\x2200" <+> frees <+> rigids
|
2013-07-11 21:30:18 +00:00
|
|
|
|
2013-07-19 15:48:41 +00:00
|
|
|
frees = P.hsep $ map prty fqs
|
|
|
|
rigids = if null rqs then P.empty else P.braces . P.hsep $ map prty rqs
|
2013-07-11 21:30:18 +00:00
|
|
|
|
2013-07-08 14:47:44 +00:00
|
|
|
cs = case constraint of
|
|
|
|
CTrue -> P.empty
|
|
|
|
CAnd [] -> P.empty
|
2013-07-19 15:48:41 +00:00
|
|
|
_ -> P.brackets (pretty Never constraint)
|
2013-07-11 21:30:18 +00:00
|
|
|
|
2013-07-08 14:47:44 +00:00
|
|
|
headers' = if Map.size headers > 0 then dict else P.empty
|
2013-07-19 15:48:41 +00:00
|
|
|
dict = P.parens . commaSep . map prettyPair $ Map.toList headers
|
|
|
|
prettyPair (n,t) = P.text n <+> P.text ":" <+> pretty Never t
|
|
|
|
|
2013-07-08 14:47:44 +00:00
|
|
|
|
2013-07-19 15:48:41 +00:00
|
|
|
extraPretty :: (PrettyType t, Crawl t) => t -> IO Doc
|
2013-07-21 04:08:08 +00:00
|
|
|
extraPretty t = pretty Never <$> addNames t
|
|
|
|
|
|
|
|
addNames :: (Crawl t) => t -> IO t
|
|
|
|
addNames value = do
|
2013-07-10 22:31:56 +00:00
|
|
|
(_, rawVars) <- runStateT (crawl getNames value) []
|
2013-07-08 14:47:44 +00:00
|
|
|
let vars = map head . List.group $ List.sort rawVars
|
2013-07-19 15:48:41 +00:00
|
|
|
suffix s = map (++s) (map (:[]) ['a'..'z'])
|
|
|
|
allVars = concatMap suffix $ ["","'","_"] ++ map show [0..]
|
2013-07-08 14:47:44 +00:00
|
|
|
okayVars = filter (`notElem` vars) allVars
|
2013-07-10 22:31:56 +00:00
|
|
|
runStateT (crawl rename value) okayVars
|
2013-07-21 04:08:08 +00:00
|
|
|
return value
|
2013-07-08 14:47:44 +00:00
|
|
|
where
|
|
|
|
getNames name vars =
|
|
|
|
case name of
|
|
|
|
Just var -> (name, var:vars)
|
|
|
|
Nothing -> (name, vars)
|
|
|
|
|
|
|
|
rename name vars =
|
|
|
|
case name of
|
|
|
|
Just var -> (name, vars)
|
|
|
|
Nothing -> (Just (head vars), tail vars)
|
2013-07-21 04:08:08 +00:00
|
|
|
|
2013-07-10 22:31:56 +00:00
|
|
|
|
|
|
|
-- Code for traversing all the type data-structures and giving
|
|
|
|
-- names to the variables embedded deep in there.
|
|
|
|
class Crawl t where
|
|
|
|
crawl :: (Maybe TypeName -> [String] -> (Maybe TypeName, [String]))
|
|
|
|
-> t
|
|
|
|
-> StateT [String] IO t
|
|
|
|
|
|
|
|
instance (Crawl t, Crawl v) => Crawl (Constraint t v) where
|
|
|
|
crawl nextState constraint =
|
|
|
|
let rnm = crawl nextState in
|
|
|
|
case constraint of
|
|
|
|
CTrue -> return CTrue
|
2013-07-19 15:48:41 +00:00
|
|
|
CSaveEnv -> return CSaveEnv
|
2013-07-10 22:31:56 +00:00
|
|
|
CEqual a b -> CEqual <$> rnm a <*> rnm b
|
|
|
|
CAnd cs -> CAnd <$> crawl nextState cs
|
|
|
|
CLet schemes c -> CLet <$> crawl nextState schemes <*> crawl nextState c
|
|
|
|
CInstance name tipe -> CInstance name <$> rnm tipe
|
|
|
|
|
|
|
|
instance Crawl a => Crawl [a] where
|
|
|
|
crawl nextState list = mapM (crawl nextState) list
|
|
|
|
|
|
|
|
instance (Crawl t, Crawl v) => Crawl (Scheme t v) where
|
|
|
|
crawl nextState (Scheme rqs fqs c headers) =
|
|
|
|
let rnm = crawl nextState in
|
|
|
|
Scheme <$> rnm rqs <*> rnm fqs <*> crawl nextState c <*> return headers
|
|
|
|
|
|
|
|
instance Crawl t => Crawl (TermN t) where
|
|
|
|
crawl nextState tipe =
|
|
|
|
case tipe of
|
|
|
|
VarN x -> VarN <$> crawl nextState x
|
|
|
|
TermN term -> TermN <$> crawl nextState term
|
|
|
|
|
|
|
|
instance Crawl t => Crawl (Term1 t) where
|
|
|
|
crawl nextState term =
|
|
|
|
let rnm = crawl nextState in
|
|
|
|
case term of
|
|
|
|
App1 a b -> App1 <$> rnm a <*> rnm b
|
|
|
|
Fun1 a b -> Fun1 <$> rnm a <*> rnm b
|
|
|
|
Var1 a -> Var1 <$> rnm a
|
|
|
|
EmptyRecord1 -> return EmptyRecord1
|
|
|
|
Record1 fields ext ->
|
|
|
|
Record1 <$> traverse (mapM rnm) fields <*> rnm ext
|
|
|
|
|
|
|
|
instance Crawl a => Crawl (UF.Point a) where
|
|
|
|
crawl nextState point = do
|
|
|
|
desc <- liftIO $ UF.descriptor point
|
|
|
|
desc' <- crawl nextState desc
|
|
|
|
liftIO $ UF.setDescriptor point desc'
|
|
|
|
return point
|
|
|
|
|
|
|
|
instance Crawl Descriptor where
|
|
|
|
crawl nextState desc = do
|
|
|
|
state <- get
|
|
|
|
let (name', state') = nextState (name desc) state
|
|
|
|
structure' <- traverse (crawl nextState) (structure desc)
|
|
|
|
put state'
|
|
|
|
return $ desc { name = name', structure = structure' }
|