3import qualified Data.Char as Char
4import qualified Data.List as List
5import qualified Data.Map as Map
6import qualified Data.UnionFind.IO as UF
8import Text.PrettyPrint as P
10import Control.Applicative ((<$>),(<*>))
11import Control.Monad.State (StateT, get, put, execStateT, runStateT)
12import Control.Monad.Error (ErrorT, Error, liftIO)
13import Data.Traversable (traverse)
15import qualified AST.PrettyPrint as PP
16import qualified AST.Type as T
17import qualified AST.Variable as Var
22type Type = TermN Variable
24type Variable = UF.Point Descriptor
26type TypeConstraint = Constraint Type Variable
28type TypeScheme = Scheme Type Variable
30type Alias a = Maybe (Var.Canonical, [(String,a)])
40 | Record1 (Map.Map String [a]) a
45 | VarN (Alias (TermN a)) a
46 | TermN (Alias (TermN a)) (Term1 (TermN a))
54termN :: (Term1 (TermN a)) -> TermN a
59record :: Map.Map String [TermN a] -> TermN a -> TermN a
61 termN (Record1 fs rec)
66data Descriptor = Descriptor
67 { structure :: Maybe (Term1 Variable)
70 , name :: Maybe TypeName
71 , copy :: Maybe Variable
73 , alias :: Alias Variable
105 Located (BasicConstraint a b)
107data BasicConstraint a b
111 | CAnd [Constraint a b]
112 | CLet [Scheme a b] (Constraint a b)
113 | CInstance SchemeName a
115type SchemeName = String
117type TypeName = Var.Canonical
119data Scheme a b = Scheme
120 { rigidQuantifiers :: [b]
121 , flexibleQuantifiers :: [b]
122 , constraint :: Constraint a b
123 , header :: Map.Map String a
131(==>) :: Type -> Type -> Type
136(<|) :: TermN a -> TermN a -> TermN a
143namedVar :: Flex -> Var.Canonical -> IO Variable
144namedVar flex name = UF.fresh $ Descriptor
145 { structure = Nothing
155variable :: Flex -> IO Variable
156variable flex = UF.fresh $ Descriptor
157 { structure = Nothing
169monoscheme :: Map.Map String a -> Scheme a b
171 Scheme [] [] (noneNoDocs CTrue) headers
176(/\) :: Constraint a b -> Constraint a b -> Constraint a b
177(/\) a@(A _ c1) b@(A _ c2) =
181 _ -> mergeOldDocs a b (CAnd [a,b])
184-- ex qs constraint == exists qs. constraint
185ex :: [Variable] -> TypeConstraint -> TypeConstraint
186ex fqs constraint@(A ann _) =
187 A ann $ CLet [Scheme [] fqs constraint Map.empty] (A ann CTrue)
190-- fl qs constraint == forall qs. constraint
191fl :: [Variable] -> TypeConstraint -> TypeConstraint
192fl rqs constraint@(A ann _) =
193 A ann $ CLet [Scheme rqs [] constraint Map.empty] (A ann CTrue)
196exists :: Error e => (Type -> ErrorT e IO TypeConstraint) -> ErrorT e IO TypeConstraint
198 do v <- liftIO $ variable Flexible
199 ex [v] <$> f (varN v)
202existsNumber :: Error e => (Type -> ErrorT e IO TypeConstraint) -> ErrorT e IO TypeConstraint
204 do v <- liftIO $ variable (Is Number)
205 ex [v] <$> f (varN v)
208-- TYPES TO PRETTY STRINGS
210instance PrettyType a => PrettyType (UF.Point a) where
212 unsafePerformIO $ fmap (pretty when) (UF.descriptor point)
215instance PrettyType t => PrettyType (Annotated a t) where
216 pretty when (A _ e) =
220instance PrettyType a => PrettyType (Term1 a) where
222 let prty = pretty Never in
225 parensIf needed (px <+> pretty App x)
234 parensIf needed (pretty Fn arg <+> P.text "->" <+> prty body)
247 Record1 fields ext ->
248 P.braces (extend <+> commaSep prettyFields)
253 | P.render prettyExt == "{}" =
256 prettyExt <+> P.text "|"
259 P.text f <+> P.text ":" <+> prty t
262 concatMap (\(f,ts) -> map (mkPretty f) ts) (Map.toList fields)
265instance PrettyType a => PrettyType (TermN a) where
269 error "problem prettifying type, probably indicates a bigger problem"
272 either alias (pretty when x)
275 either alias (pretty when t1)
277 either maybeAlias doc =
281 P.hang (PP.pretty name) 2 (P.sep (map (pretty App . snd) args))
284instance PrettyType Descriptor where
286 case (alias desc, structure desc, name desc) of
287 (Just (name, args), _, _) ->
288 P.hang (PP.pretty name) 4 (P.sep (map (pretty App . snd) args))
294 | Var.isTuple name ->
295 P.parens . P.text $ replicate (read (drop 6 (Var.toString name)) - 1) ','
297 P.text (Var.toString name)
302instance (PrettyType a, PrettyType b) => PrettyType (BasicConstraint a b) where
303 pretty _ constraint =
304 let prty = pretty Never in
306 CTrue -> P.text "True"
307 CSaveEnv -> P.text "SaveTheEnvironment!!!"
308 CEqual a b -> prty a <+> P.text "=" <+> prty b
309 CAnd [] -> P.text "True"
312 P.parens . P.sep $ P.punctuate (P.text " and") (map (pretty Never) cs)
314 CLet [Scheme [] fqs constraint header] (A _ CTrue) | Map.null header ->
315 P.sep [ binder, pretty Never c ]
317 mergeExists vs (A _ c) =
319 CLet [Scheme [] fqs' c' _] (A _ CTrue) -> mergeExists (vs ++ fqs') c'
322 (fqs', c) = mergeExists fqs constraint
324 binder = if null fqs' then P.empty else
325 P.text "\x2203" <+> P.hsep (map (pretty Never) fqs') <> P.text "."
327 CLet schemes constraint ->
328 P.fsep [ P.hang (P.text "let") 4 (P.brackets . commaSep $ map (pretty Never) schemes)
329 , P.text "in", pretty Never constraint ]
331 CInstance name tipe ->
332 P.text name <+> P.text "<" <+> prty tipe
335instance (PrettyType a, PrettyType b) => PrettyType (Scheme a b) where
336 pretty _ (Scheme rqs fqs (A _ constraint) headers) =
337 P.sep [ forall, cs, headers' ]
341 forall = if null rqs && null fqs then P.empty else
342 P.text "\x2200" <+> frees <+> rigids
344 frees = P.hsep $ map prty fqs
345 rigids = if null rqs then P.empty else P.braces . P.hsep $ map prty rqs
347 cs = case constraint of
350 _ -> P.brackets (pretty Never constraint)
352 headers' = if Map.size headers > 0 then dict else P.empty
353 dict = P.parens . commaSep . map prettyPair $ Map.toList headers
354 prettyPair (n,t) = P.text n <+> P.text ":" <+> pretty Never t
357extraPretty :: (PrettyType t, Crawl t) => t -> IO Doc
359 pretty Never <$> addNames t
362-- ADDING NAMES TO TYPES
364addNames :: (Crawl t) => t -> IO t
366 do (rawVars, _, _, _) <- execStateT (crawl getNames value) ([], 0, 0, 0)
368 let vars = map head . List.group $ List.sort rawVars
370 let suffix s = map (++s) (map (:[]) ['a'..'z'])
372 let allVars = concatMap suffix $ ["","'","_"] ++ map show [ (0 :: Int) .. ]
374 let okayVars = filter (`notElem` vars) allVars
376 runStateT (crawl rename value) (okayVars, 0, 0, 0)
380 getNames desc state@(vars, a, b, c) =
381 let name' = name desc in
383 Just (Var.Canonical _ var) -> (name', (var:vars, a, b, c))
386 rename desc state@(vars, a, b, c) =
388 Just var -> (Just var, state)
391 Is Number -> (local $ "number" ++ replicate a '\'', (vars, a+1, b, c))
392 Is Comparable -> (local $ "comparable" ++ replicate b '\'', (vars, a, b+1, c))
393 Is Appendable -> (local $ "appendable" ++ replicate c '\'', (vars, a, b, c+1))
394 _ -> (local $ head vars, (tail vars, a, b, c))
396 local v = Just (Var.local v)
399-- CRAWLING OVER TYPES
401type CrawlState = ([String], Int, Int, Int)
404-- Code for traversing all the type data-structures and giving
405-- names to the variables embedded deep in there.
407 crawl :: (Descriptor -> CrawlState -> (Maybe TypeName, CrawlState))
409 -> StateT CrawlState IO t
412instance Crawl e => Crawl (Annotated a e) where
413 crawl nextState (A ann e) =
414 A ann <$> crawl nextState e
417instance (Crawl t, Crawl v) => Crawl (BasicConstraint t v) where
418 crawl nextState constraint =
419 let rnm = crawl nextState in
421 CTrue -> return CTrue
422 CSaveEnv -> return CSaveEnv
423 CEqual a b -> CEqual <$> rnm a <*> rnm b
424 CAnd cs -> CAnd <$> crawl nextState cs
425 CLet schemes c -> CLet <$> crawl nextState schemes <*> crawl nextState c
426 CInstance name tipe -> CInstance name <$> rnm tipe
429instance Crawl a => Crawl [a] where
430 crawl nextState list =
431 mapM (crawl nextState) list
434instance (Crawl t, Crawl v) => Crawl (Scheme t v) where
435 crawl nextState (Scheme rqs fqs c headers) =
436 let rnm = crawl nextState
441 <*> crawl nextState c
445instance Crawl t => Crawl (TermN t) where
446 crawl nextState tipe =
449 return (PlaceHolder name)
452 VarN a <$> crawl nextState x
455 TermN a <$> crawl nextState term
458instance Crawl t => Crawl (Term1 t) where
459 crawl nextState term =
460 let rnm = crawl nextState in
463 App1 <$> rnm a <*> rnm b
466 Fun1 <$> rnm a <*> rnm b
474 Record1 fields ext ->
476 <$> traverse (mapM rnm) fields
480instance Crawl a => Crawl (UF.Point a) where
481 crawl nextState point =
482 do desc <- liftIO $ UF.descriptor point
483 desc' <- crawl nextState desc
484 liftIO $ UF.setDescriptor point desc'
488instance Crawl Descriptor where
489 crawl nextState desc =
491 let (name', state') = nextState desc state
492 structure' <- traverse (crawl nextState) (structure desc)
494 return $ desc { name = name', structure = structure' }
497-- TODO: Attach resulting type to the descriptor so that you
498-- never have to do extra work, particularly nice for aliased types
499toSrcType :: Variable -> IO T.CanonicalType
504 do desc <- UF.descriptor v
505 srcType <- maybe (backupSrcType desc) termToSrcType (structure desc)
511 do args' <- mapM (\(arg,tvar) -> (,) arg <$> go tvar) args
512 return (T.Aliased name args' srcType)
514 backupSrcType :: Descriptor -> IO T.CanonicalType
517 Just v@(Var.Canonical _ x@(c:_))
526 [ "Problem converting the following type "
527 , "from a type-checker type to a source-syntax type:"
528 , P.render (pretty Never var)
531 termToSrcType :: Term1 Variable -> IO T.CanonicalType
539 return $ T.App f (args ++ [b'])
541 return $ T.App a' [b']
544 T.Lambda <$> go a <*> go b
550 return $ T.Record [] Nothing
552 Record1 tfields extension ->
553 do fields' <- traverse (mapM go) tfields
554 let fields = concat [ map ((,) name) ts | (name,ts) <- Map.toList fields' ]
555 ext' <- dealias <$> go extension
558 T.Record fs ext -> T.Record (fs ++ fields) ext
559 T.Var _ -> T.Record fields (Just ext')
560 _ -> error "Used toSrcType on a type that is not well-formed"
562 dealias :: T.CanonicalType -> T.CanonicalType
565 T.Aliased _ args tipe' ->
577collectApps :: Variable -> IO AppStructure
582 desc <- UF.descriptor var
583 case (structure desc, vars) of
586 Just n | Var.isList n -> return (List v)
591 Just n | Var.isTuple n -> return (Tuple vs)
596 App1 a b -> go (vars ++ [b]) a
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list