Add pretty printing for type constraints.
Convert source-syntax types into type-checker types and print them with pretty type variables. Generate constraints for let-expressions using type annotations. Build test function to turn strings into type constraints.
This commit is contained in:
parent
96fd5bfd78
commit
0ed72056b6
4 changed files with 226 additions and 51 deletions
|
@ -12,7 +12,6 @@ import qualified Parse.Type as Type
|
||||||
import Parse.Binop
|
import Parse.Binop
|
||||||
import Parse.Literal
|
import Parse.Literal
|
||||||
|
|
||||||
import SourceSyntax.PrettyPrint
|
|
||||||
import SourceSyntax.Location as Location
|
import SourceSyntax.Location as Location
|
||||||
import SourceSyntax.Pattern hiding (tuple,list)
|
import SourceSyntax.Pattern hiding (tuple,list)
|
||||||
import qualified SourceSyntax.Literal as Literal
|
import qualified SourceSyntax.Literal as Literal
|
||||||
|
@ -215,7 +214,7 @@ typeAnnotation = TypeAnnotation <$> try start <*> Type.expr
|
||||||
def :: IParser (Def t v)
|
def :: IParser (Def t v)
|
||||||
def = typeAnnotation <|> assignExpr
|
def = typeAnnotation <|> assignExpr
|
||||||
|
|
||||||
parseDef str =
|
attempt f parser str =
|
||||||
case iParse def "" str of
|
case iParse parser "" str of
|
||||||
Right result -> Right result
|
Right result -> f result
|
||||||
Left err -> Left $ "Parse error at " ++ show err
|
Left err -> error $ "Parse error at " ++ show err
|
||||||
|
|
|
@ -1,25 +1,45 @@
|
||||||
module Type.Constrain.Expression where
|
module Type.Constrain.Expression where
|
||||||
|
|
||||||
import Control.Arrow (second)
|
|
||||||
import Control.Applicative ((<$>))
|
|
||||||
import qualified Data.List as List
|
import qualified Data.List as List
|
||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
import qualified Control.Monad as Monad
|
|
||||||
import Data.Map ((!))
|
import Data.Map ((!))
|
||||||
|
import Control.Arrow (second)
|
||||||
|
import Control.Applicative ((<$>),(<*>))
|
||||||
|
import qualified Control.Monad as Monad
|
||||||
|
import Control.Monad.State
|
||||||
|
import Data.Traversable (traverse)
|
||||||
|
|
||||||
import SourceSyntax.Location as Loc
|
import SourceSyntax.Location as Loc
|
||||||
import SourceSyntax.Pattern (Pattern(PVar))
|
import SourceSyntax.Pattern (Pattern(PVar))
|
||||||
import SourceSyntax.Expression
|
import SourceSyntax.Expression
|
||||||
|
import qualified SourceSyntax.Type as SrcT
|
||||||
import Type.Type hiding (Descriptor(..))
|
import Type.Type hiding (Descriptor(..))
|
||||||
import Type.Fragment
|
import Type.Fragment
|
||||||
import Type.Environment as Env
|
import qualified Type.Environment as Env
|
||||||
import qualified Type.Constrain.Literal as Literal
|
import qualified Type.Constrain.Literal as Literal
|
||||||
import qualified Type.Constrain.Pattern as Pattern
|
import qualified Type.Constrain.Pattern as Pattern
|
||||||
|
|
||||||
|
{-- Testing section --}
|
||||||
|
import SourceSyntax.PrettyPrint
|
||||||
|
import Parse.Expression
|
||||||
|
import Parse.Helpers (iParse)
|
||||||
|
|
||||||
constrain :: Environment -> LExpr a b -> Type -> IO TypeConstraint
|
test str =
|
||||||
|
case iParse expr "" str of
|
||||||
|
Left err -> error $ "Parse error at " ++ show err
|
||||||
|
Right expression -> do
|
||||||
|
env <- Env.initialEnvironment
|
||||||
|
var <- flexibleVar
|
||||||
|
constraint <- constrain env expression (VarN var)
|
||||||
|
prettyNames constraint
|
||||||
|
print (pretty constraint)
|
||||||
|
print (pretty var)
|
||||||
|
return ()
|
||||||
|
{-- todo: remove testing code --}
|
||||||
|
|
||||||
|
constrain :: Env.Environment -> LExpr a b -> Type -> IO TypeConstraint
|
||||||
constrain env (L _ _ expr) tipe =
|
constrain env (L _ _ expr) tipe =
|
||||||
let list t = TermN (App1 (Env.get env builtin "[]") t) in
|
let list t = TermN (App1 (Env.get env Env.builtin "[_]") t) in
|
||||||
case expr of
|
case expr of
|
||||||
Literal lit -> return $ Literal.constrain env lit tipe
|
Literal lit -> return $ Literal.constrain env lit tipe
|
||||||
|
|
||||||
|
@ -41,7 +61,7 @@ constrain env (L _ _ expr) tipe =
|
||||||
exists $ \t2 -> do
|
exists $ \t2 -> do
|
||||||
c1 <- constrain env e1 t1
|
c1 <- constrain env e1 t1
|
||||||
c2 <- constrain env e2 t2
|
c2 <- constrain env e2 t2
|
||||||
return $ CAnd [ c1, c2, (Env.get env value op) === (t1 ==> t2 ==> tipe) ]
|
return $ CAnd [ c1, c2, op <? (t1 ==> t2 ==> tipe) ]
|
||||||
|
|
||||||
Lambda p e ->
|
Lambda p e ->
|
||||||
exists $ \t1 ->
|
exists $ \t1 ->
|
||||||
|
@ -60,7 +80,7 @@ constrain env (L _ _ expr) tipe =
|
||||||
|
|
||||||
MultiIf branches -> CAnd <$> mapM constrain' branches
|
MultiIf branches -> CAnd <$> mapM constrain' branches
|
||||||
where
|
where
|
||||||
bool = Env.get env builtin "Bool"
|
bool = Env.get env Env.builtin "Bool"
|
||||||
constrain' (b,e) = do
|
constrain' (b,e) = do
|
||||||
cb <- constrain env b bool
|
cb <- constrain env b bool
|
||||||
ce <- constrain env e tipe
|
ce <- constrain env e tipe
|
||||||
|
@ -135,9 +155,8 @@ constrain env (L _ _ expr) tipe =
|
||||||
|
|
||||||
|
|
||||||
Markdown _ ->
|
Markdown _ ->
|
||||||
return $ tipe === Env.get env builtin "Element"
|
return $ tipe === Env.get env Env.builtin "Element"
|
||||||
|
|
||||||
{--
|
|
||||||
Let defs body ->
|
Let defs body ->
|
||||||
do c <- constrain env body tipe
|
do c <- constrain env body tipe
|
||||||
(schemes, rqs, fqs, header, c2, c1) <-
|
(schemes, rqs, fqs, header, c2, c1) <-
|
||||||
|
@ -149,15 +168,17 @@ constrain env (L _ _ expr) tipe =
|
||||||
(c1 /\ c))
|
(c1 /\ c))
|
||||||
|
|
||||||
|
|
||||||
constrainDef env info (name, qs, expr, maybeTipe) =
|
constrainDef env info (pattern, expr, maybeTipe) =
|
||||||
let (schemes, rigidQuantifiers, flexibleQuantifiers, headers, c2, c1) = info in
|
let qs = [] -- should come from the def, but I'm not sure what would live there...
|
||||||
case maybeTipe of
|
(schemes, rigidQuantifiers, flexibleQuantifiers, headers, c2, c1) = info
|
||||||
Just tipe ->
|
in
|
||||||
|
case (pattern, maybeTipe) of
|
||||||
|
(PVar name, Just tipe) ->
|
||||||
do flexiVars <- mapM (\_ -> flexibleVar) qs
|
do flexiVars <- mapM (\_ -> flexibleVar) qs
|
||||||
let inserts = zipWith (\arg typ -> Map.insert arg (VarN typ)) qs flexiVars
|
let inserts = zipWith (\arg typ -> Map.insert arg (VarN typ)) qs flexiVars
|
||||||
env' = env { value = List.foldl' (\x f -> f x) (value env) inserts }
|
env' = env { Env.value = List.foldl' (\x f -> f x) (Env.value env) inserts }
|
||||||
typ = error "This should be the internal representation of the user defined type."
|
typ <- instantiateType tipe
|
||||||
scheme = Scheme { rigidQuantifiers = [],
|
let scheme = Scheme { rigidQuantifiers = [],
|
||||||
flexibleQuantifiers = flexiVars,
|
flexibleQuantifiers = flexiVars,
|
||||||
constraint = CTrue,
|
constraint = CTrue,
|
||||||
header = Map.singleton name typ }
|
header = Map.singleton name typ }
|
||||||
|
@ -169,12 +190,12 @@ constrainDef env info (name, qs, expr, maybeTipe) =
|
||||||
, c2
|
, c2
|
||||||
, fl rigidQuantifiers c /\ c1 )
|
, fl rigidQuantifiers c /\ c1 )
|
||||||
|
|
||||||
Nothing ->
|
(PVar name, Nothing) ->
|
||||||
do var <- flexibleVar
|
do var <- flexibleVar
|
||||||
rigidVars <- mapM (\_ -> rigidVar) qs
|
rigidVars <- mapM (\_ -> rigidVar) qs
|
||||||
let tipe = VarN var
|
let tipe = VarN var
|
||||||
inserts = zipWith (\arg typ -> Map.insert arg (VarN typ)) qs rigidVars
|
inserts = zipWith (\arg typ -> Map.insert arg (VarN typ)) qs rigidVars
|
||||||
env' = env { value = List.foldl' (\x f -> f x) (value env) inserts }
|
env' = env { Env.value = List.foldl' (\x f -> f x) (Env.value env) inserts }
|
||||||
c <- constrain env' expr tipe
|
c <- constrain env' expr tipe
|
||||||
return ( schemes
|
return ( schemes
|
||||||
, rigidVars ++ rigidQuantifiers
|
, rigidVars ++ rigidQuantifiers
|
||||||
|
@ -183,18 +204,45 @@ constrainDef env info (name, qs, expr, maybeTipe) =
|
||||||
, c /\ c2
|
, c /\ c2
|
||||||
, c1 )
|
, c1 )
|
||||||
|
|
||||||
--collapseDefs :: [Def t v] -> [(String, [String], LExpr t v, Maybe Type)]
|
instantiateType :: SrcT.Type -> IO Type
|
||||||
collapseDefs definitions =
|
instantiateType sourceType = evalStateT (go sourceType) Map.empty
|
||||||
map (\(name, (expr, tipe)) -> (name, expr, tipe)) defPairs
|
|
||||||
where
|
where
|
||||||
defPairs = Map.toList (go Map.empty Map.empty definitions)
|
go :: SrcT.Type -> StateT (Map.Map String Variable) IO Type
|
||||||
|
go sourceType =
|
||||||
|
case sourceType of
|
||||||
|
SrcT.Lambda t1 t2 -> TermN <$> (Fun1 <$> go t1 <*> go t2)
|
||||||
|
|
||||||
go defs typs [] = Map.union (Map.intersectionWith (\f t -> f (Just t)) defs typs)
|
SrcT.Var x -> do
|
||||||
(Map.map ($ Nothing) (Map.difference defs typs))
|
dict <- get
|
||||||
go defs typs (d:ds) =
|
case Map.lookup x dict of
|
||||||
|
Just var -> return (VarN var)
|
||||||
|
Nothing -> do
|
||||||
|
var <- liftIO $ namedVar x -- should this be Constant or Flexible?
|
||||||
|
put (Map.insert x var dict)
|
||||||
|
return (VarN var)
|
||||||
|
|
||||||
|
SrcT.Data name ts -> do
|
||||||
|
ts' <- mapM go ts
|
||||||
|
return $ foldr (\t result -> TermN $ App1 t result) (error "not sure how to look this up yet") ts'
|
||||||
|
|
||||||
|
SrcT.EmptyRecord -> return (TermN EmptyRecord1)
|
||||||
|
|
||||||
|
SrcT.Record fields ext ->
|
||||||
|
TermN <$> (Record1 <$> traverse (mapM go) fields <*> go ext)
|
||||||
|
|
||||||
|
collapseDefs :: [Def t v] -> [(Pattern, LExpr t v, Maybe SrcT.Type)]
|
||||||
|
collapseDefs = go [] Map.empty Map.empty
|
||||||
|
where
|
||||||
|
go output defs typs [] =
|
||||||
|
output ++ concatMap Map.elems [
|
||||||
|
Map.intersectionWithKey (\k v t -> (PVar k, v, Just t)) defs typs,
|
||||||
|
Map.mapWithKey (\k v -> (PVar k, v, Nothing)) (Map.difference defs typs) ]
|
||||||
|
go output defs typs (d:ds) =
|
||||||
case d of
|
case d of
|
||||||
Def name body ->
|
Def (PVar name) body ->
|
||||||
go (Map.insert name ((,) body) defs) typs ds
|
go output (Map.insert name body defs) typs ds
|
||||||
|
Def pattern body ->
|
||||||
|
go ((pattern, body, Nothing) : output) defs typs ds
|
||||||
TypeAnnotation name typ ->
|
TypeAnnotation name typ ->
|
||||||
go defs (Map.insert name typ typs) ds
|
go output defs (Map.insert name typ typs) ds
|
||||||
--}
|
--}
|
|
@ -15,19 +15,27 @@ data Environment = Environment {
|
||||||
initialEnvironment :: IO Environment
|
initialEnvironment :: IO Environment
|
||||||
initialEnvironment = do
|
initialEnvironment = do
|
||||||
let mkPair name = fmap ((,) name . VarN) (namedVar name)
|
let mkPair name = fmap ((,) name . VarN) (namedVar name)
|
||||||
list <- mkPair "[]"
|
list <- mkPair "[_]"
|
||||||
prims <- mapM mkPair ["Int","Float","Char","Bool","Element"]
|
int <- mkPair "Int"
|
||||||
|
prims <- mapM mkPair ["Float","Char","Bool","Element"]
|
||||||
|
let builtins = list : int : prims
|
||||||
|
|
||||||
cons <- do v <- flexibleVar
|
cons <- do v <- flexibleVar
|
||||||
let vlist = TermN (App1 (snd list) (VarN v))
|
let vlist = TermN (App1 (snd list) (VarN v))
|
||||||
return ([v], VarN v ==> vlist ==> vlist)
|
return ([v], VarN v ==> vlist ==> vlist)
|
||||||
|
|
||||||
let builtins = list : prims
|
nil <- do v <- flexibleVar
|
||||||
|
return ([v], TermN (App1 (snd list) (VarN v)))
|
||||||
|
|
||||||
|
let add = snd int ==> snd int ==> snd int
|
||||||
|
|
||||||
return $ Environment {
|
return $ Environment {
|
||||||
constructor = Map.singleton "::" cons,
|
constructor = Map.fromList [("::", cons), ("[]", nil)],
|
||||||
builtin = Map.fromList builtins,
|
builtin = Map.fromList builtins,
|
||||||
value = Map.empty
|
value = Map.empty -- Map.fromList [("+", add)]
|
||||||
}
|
}
|
||||||
|
|
||||||
get :: Environment -> (Environment -> Map.Map String a) -> String -> a
|
get :: Environment -> (Environment -> Map.Map String a) -> String -> a
|
||||||
get env subDict key = subDict env ! key
|
get env subDict key = Map.findWithDefault err key (subDict env)
|
||||||
|
where
|
||||||
|
err = error $ "Could not find '" ++ key ++ "' in the type environment."
|
|
@ -1,9 +1,14 @@
|
||||||
module Type.Type where
|
module Type.Type where
|
||||||
|
|
||||||
import Control.Applicative ((<$>))
|
import qualified Data.List as List
|
||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
import qualified Data.UnionFind.IO as UF
|
import qualified Data.UnionFind.IO as UF
|
||||||
|
import SourceSyntax.PrettyPrint
|
||||||
|
import Text.PrettyPrint as P
|
||||||
import System.IO.Unsafe
|
import System.IO.Unsafe
|
||||||
|
import Control.Applicative ((<$>),(<*>))
|
||||||
|
import Control.Monad.State
|
||||||
|
import Data.Traversable (traverse)
|
||||||
|
|
||||||
data Term1 a
|
data Term1 a
|
||||||
= App1 a a
|
= App1 a a
|
||||||
|
@ -16,6 +21,7 @@ data Term1 a
|
||||||
data TermN a
|
data TermN a
|
||||||
= VarN a
|
= VarN a
|
||||||
| TermN (Term1 (TermN a))
|
| TermN (Term1 (TermN a))
|
||||||
|
deriving Show
|
||||||
|
|
||||||
record fs rec = TermN (Record1 fs rec)
|
record fs rec = TermN (Record1 fs rec)
|
||||||
|
|
||||||
|
@ -34,7 +40,7 @@ data Scheme a b = Scheme {
|
||||||
rigidQuantifiers :: [b],
|
rigidQuantifiers :: [b],
|
||||||
flexibleQuantifiers :: [b],
|
flexibleQuantifiers :: [b],
|
||||||
constraint :: Constraint a b,
|
constraint :: Constraint a b,
|
||||||
header :: Map.Map String a -- mapping from names to types
|
header :: Map.Map String a
|
||||||
} deriving Show
|
} deriving Show
|
||||||
|
|
||||||
monoscheme headers = Scheme [] [] CTrue headers
|
monoscheme headers = Scheme [] [] CTrue headers
|
||||||
|
@ -45,7 +51,7 @@ data Descriptor = Descriptor {
|
||||||
flex :: Flex,
|
flex :: Flex,
|
||||||
name :: Maybe TypeName,
|
name :: Maybe TypeName,
|
||||||
mark :: Int
|
mark :: Int
|
||||||
}
|
} deriving Show
|
||||||
|
|
||||||
noRank = -1
|
noRank = -1
|
||||||
outermostRank = 0 :: Int
|
outermostRank = 0 :: Int
|
||||||
|
@ -114,12 +120,126 @@ exists f = do
|
||||||
instance Show a => Show (UF.Point a) where
|
instance Show a => Show (UF.Point a) where
|
||||||
show point = unsafePerformIO $ fmap show (UF.descriptor point)
|
show point = unsafePerformIO $ fmap show (UF.descriptor point)
|
||||||
|
|
||||||
instance Show Descriptor where
|
instance Pretty a => Pretty (UF.Point a) where
|
||||||
show desc = case name desc of
|
pretty point = unsafePerformIO $ fmap pretty (UF.descriptor point)
|
||||||
Just n -> n
|
|
||||||
Nothing -> show (structure desc)
|
|
||||||
|
|
||||||
instance Show a => Show (TermN a) where
|
instance Pretty a => Pretty (Term1 a) where
|
||||||
show term = case term of
|
pretty term =
|
||||||
VarN v -> show v
|
case term of
|
||||||
TermN t -> "(" ++ show t ++ ")"
|
App1 f x -> pretty f <+> pretty x
|
||||||
|
Fun1 arg body -> pretty arg <+> P.text "->" <+> pretty body
|
||||||
|
Var1 x -> pretty x
|
||||||
|
EmptyRecord1 -> P.braces P.empty
|
||||||
|
Record1 fields ext ->
|
||||||
|
P.braces (pretty ext <+> P.text "|" <+> P.sep (P.punctuate P.comma prettyFields))
|
||||||
|
where
|
||||||
|
mkPretty f t = P.text f <+> P.text ":" <+> pretty t
|
||||||
|
prettyFields = concatMap (\(f,ts) -> map (mkPretty f) ts) (Map.toList fields)
|
||||||
|
|
||||||
|
instance Pretty a => Pretty (TermN a) where
|
||||||
|
pretty term =
|
||||||
|
case term of
|
||||||
|
VarN x -> pretty x
|
||||||
|
TermN t1 -> pretty t1
|
||||||
|
|
||||||
|
instance Pretty Descriptor where
|
||||||
|
pretty desc =
|
||||||
|
case (structure desc, name desc) of
|
||||||
|
(Just term, _) -> pretty term
|
||||||
|
(_, Just name) -> P.text name
|
||||||
|
_ -> P.text "?"
|
||||||
|
|
||||||
|
instance (Pretty a, Pretty b) => Pretty (Constraint a b) where
|
||||||
|
pretty constraint =
|
||||||
|
case constraint of
|
||||||
|
CTrue -> P.text "True"
|
||||||
|
CEqual a b -> pretty a <+> P.text "=" <+> pretty b
|
||||||
|
CAnd [] -> P.text "True"
|
||||||
|
|
||||||
|
CAnd (c:cs) ->
|
||||||
|
P.parens . P.sep $ pretty c : (map (\c -> P.text "and" <+> pretty c) cs)
|
||||||
|
|
||||||
|
CLet [Scheme [] fqs constraint header] CTrue | Map.null header ->
|
||||||
|
P.hang binder 2 (pretty constraint)
|
||||||
|
where
|
||||||
|
binder = if null fqs then P.empty else
|
||||||
|
P.text "exists" <+> P.hsep (map pretty fqs) <> P.text "."
|
||||||
|
|
||||||
|
CLet schemes constraint ->
|
||||||
|
P.vcat [ P.hang (P.text "let") 4 (P.brackets . P.sep . P.punctuate P.comma $ map pretty schemes)
|
||||||
|
, P.text "in " <+> pretty constraint ]
|
||||||
|
|
||||||
|
CInstance name tipe ->
|
||||||
|
P.text name <+> P.text "<" <+> pretty tipe
|
||||||
|
|
||||||
|
instance (Pretty a, Pretty b) => Pretty (Scheme a b) where
|
||||||
|
pretty (Scheme rqs fqs constraint headers) =
|
||||||
|
P.sep [ forall <+> frees <+> rigids, cs, headers' ]
|
||||||
|
where
|
||||||
|
forall = if Map.size headers + length rqs /= 0 then P.text "forall" else P.empty
|
||||||
|
frees = P.hsep $ map pretty fqs
|
||||||
|
rigids = if length rqs > 0 then P.braces . P.hsep $ map pretty rqs else empty
|
||||||
|
cs = case constraint of
|
||||||
|
CTrue -> P.empty
|
||||||
|
CAnd [] -> P.empty
|
||||||
|
_ -> P.brackets (pretty constraint)
|
||||||
|
headers' = if Map.size headers > 0 then dict else P.empty
|
||||||
|
dict = P.parens . P.sep . P.punctuate P.comma . map prettyPair $ Map.toList headers
|
||||||
|
prettyPair (n,t) = P.text n <+> P.text ":" <+> pretty t
|
||||||
|
|
||||||
|
|
||||||
|
prettyNames constraint = do
|
||||||
|
(_, rawVars) <- fold constraint [] getNames
|
||||||
|
let vars = map head . List.group $ List.sort rawVars
|
||||||
|
letters = map (:[]) ['a'..'z']
|
||||||
|
suffix s = map (++s)
|
||||||
|
allVars = letters ++ suffix "'" letters ++ concatMap (\n -> suffix (show n) letters) [0..]
|
||||||
|
okayVars = filter (`notElem` vars) allVars
|
||||||
|
fold constraint okayVars rename
|
||||||
|
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)
|
||||||
|
|
||||||
|
fold constraint initialState func =
|
||||||
|
runStateT (prettyName constraint) initialState
|
||||||
|
where
|
||||||
|
prettyName constraint =
|
||||||
|
case constraint of
|
||||||
|
CTrue -> return CTrue
|
||||||
|
CEqual a b -> CEqual <$> prettyTypeName a <*> prettyTypeName b
|
||||||
|
CAnd cs -> CAnd <$> mapM prettyName cs
|
||||||
|
CLet schemes c -> CLet <$> mapM prettySchemeName schemes <*> prettyName c
|
||||||
|
CInstance name tipe -> CInstance name <$> prettyTypeName tipe
|
||||||
|
|
||||||
|
prettySchemeName (Scheme rqs fqs c headers) =
|
||||||
|
Scheme <$> mapM prettyVarName rqs <*> mapM prettyVarName fqs <*> prettyName c <*> return headers
|
||||||
|
|
||||||
|
prettyVarName point = do
|
||||||
|
state <- get
|
||||||
|
put =<< do desc <- liftIO $ UF.descriptor point
|
||||||
|
let (name', state') = func (name desc) state
|
||||||
|
liftIO $ UF.setDescriptor point (desc { name = name' })
|
||||||
|
return state'
|
||||||
|
return point
|
||||||
|
|
||||||
|
prettyTypeName tipe =
|
||||||
|
case tipe of
|
||||||
|
VarN x -> VarN <$> prettyVarName x
|
||||||
|
TermN term -> TermN <$> prettyTermName term
|
||||||
|
|
||||||
|
prettyTermName term =
|
||||||
|
case term of
|
||||||
|
App1 a b -> App1 <$> prettyTypeName a <*> prettyTypeName b
|
||||||
|
Fun1 a b -> Fun1 <$> prettyTypeName a <*> prettyTypeName b
|
||||||
|
Var1 a -> Var1 <$> prettyTypeName a
|
||||||
|
EmptyRecord1 -> return EmptyRecord1
|
||||||
|
Record1 fields ext -> Record1 <$> fields' <*> prettyTypeName ext
|
||||||
|
where
|
||||||
|
fields' = traverse (mapM prettyTypeName) fields
|
||||||
|
|
Loading…
Reference in a new issue