Search code examples
haskelltypesabstract-syntax-treepretty-print

Haskell: Pretty print infix and prefix


I have a type to represent haskell types:

data Type 
    = TApp Type Type
    | TVar Name
    | TLit Name
infixl 8 `TApp`

-- a -> b
aToB = TLit "Fun" `TApp` TVar "a" `TApp` TVar "b"

-- Maybe (IO Int)
maybeIOInt = TLit "Maybe" `TApp` (TLit "IO" `TApp` TLit "Int")

I want to print it as haskell does, namely, literals that are symbols are printed infix while other literal are printed prefix. also parenthesis should be added when necessary:

show aToB = "a -> b"
show maybeIOInt = "Maybe (IO Int)"

show ast = ???

How can I implement this?


Solution

  • The usual way to do this is thread through a precedence variable to your printing function. Also, you almost always should prefer a pretty printing library instead of just using raw strings (both for performance reasons, and ease). GHC ships with pretty and I also recommend the newer prettyprinter.

    Using the former (and assuming type Name = String):

    import Text.PrettyPrint.HughesPJ
    
    prettyType :: Type -> Doc
    prettyType = go 0
      where
        go :: Int -> Type -> Doc
        go _ (TVar x) = text x
        go _ (TLit n) = text n
        go n (TLit "Fun" `TApp` l `TApp` r) = maybeParens (n > 0) (go 1 l <+> text "->" <+> go 0 r)
        go n (l `TApp` r) = maybeParens (n > 1) (go 1 l <+> go 2 r)