twee-2.0: src/Twee/Pretty.hs
-- | Pretty-printing of terms and assorted other values.
{-# LANGUAGE Rank2Types #-}
module Twee.Pretty(module Twee.Pretty, module Text.PrettyPrint.HughesPJClass, Pretty(..)) where
import Text.PrettyPrint.HughesPJClass hiding (empty)
import qualified Text.PrettyPrint.HughesPJClass as PP
import qualified Data.Map as Map
import Data.Map(Map)
import qualified Data.Set as Set
import Data.Set(Set)
import Data.Ratio
import Twee.Term
-- * Miscellaneous 'Pretty' instances and utilities.
prettyPrint :: Pretty a => a -> IO ()
prettyPrint x = putStrLn (prettyShow x)
pPrintParen :: Bool -> Doc -> Doc
pPrintParen True d = parens d
pPrintParen False d = d
pPrintEmpty :: Doc
pPrintEmpty = PP.empty
instance Pretty Doc where pPrint = id
pPrintTuple :: [Doc] -> Doc
pPrintTuple = parens . fsep . punctuate comma
instance Pretty a => Pretty (Set a) where
pPrint = pPrintSet . map pPrint . Set.toList
pPrintSet :: [Doc] -> Doc
pPrintSet = braces . fsep . punctuate comma
instance Pretty Var where
pPrint (V n) =
text $
vars !! (n `mod` length vars):
case n `div` length vars of
0 -> ""
m -> show (m+1)
where
vars = "XYZWVUTS"
instance (Pretty k, Pretty v) => Pretty (Map k v) where
pPrint = pPrintSet . map binding . Map.toList
where
binding (x, v) = hang (pPrint x <+> text "=>") 2 (pPrint v)
instance (Eq a, Integral a, Pretty a) => Pretty (Ratio a) where
pPrint a
| denominator a == 1 = pPrint (numerator a)
| otherwise = text "(" <+> pPrint (numerator a) <> text "/" <> pPrint (denominator a) <+> text ")"
-- | Generate a list of candidate names for pretty-printing.
supply :: [String] -> [String]
supply names =
names ++
[ name ++ show i | i <- [2..], name <- names ]
-- * Pretty-printing of terms.
instance Pretty f => Pretty (Fun f) where
pPrintPrec l p = pPrintPrec l p . fun_value
instance PrettyTerm f => PrettyTerm (Fun f) where
termStyle f = termStyle (fun_value f)
instance PrettyTerm f => Pretty (Term f) where
pPrintPrec l p (Var x) = pPrintPrec l p x
pPrintPrec l p (App f xs) =
pPrintTerm (termStyle f) l p (pPrint f) (termListToList xs)
instance PrettyTerm f => Pretty (TermList f) where
pPrintPrec _ _ = pPrint . termListToList
instance PrettyTerm f => Pretty (Subst f) where
pPrint sub = text "{" <> fsep (punctuate (text ",") docs) <> text "}"
where
docs =
[ hang (pPrint x <+> text "->") 2 (pPrint t)
| (x, t) <- listSubst sub ]
-- | A class for customising the printing of function symbols.
class Pretty f => PrettyTerm f where
termStyle :: f -> TermStyle
termStyle _ = curried
-- | Defines how to print out a function symbol.
newtype TermStyle =
TermStyle {
-- | Takes the pretty-printing level, precedence,
-- pretty-printed function symbol and list of arguments and prints the term.
pPrintTerm :: forall a. Pretty a => PrettyLevel -> Rational -> Doc -> [a] -> Doc }
invisible, curried, uncurried, prefix, postfix :: TermStyle
-- | For operators like @$@ that should be printed as a blank space.
invisible =
TermStyle $ \l p d ->
let
f [] = d
f [t] = pPrintPrec l p t
f (t:ts) =
pPrintParen (p > 10) $
pPrint t <+>
(hsep (map (pPrintPrec l 11) ts))
in f
-- | For functions that should be printed curried.
curried =
TermStyle $ \l p d ->
let
f [] = d
f xs =
pPrintParen (p > 10) $
d <+>
(hsep (map (pPrintPrec l 11) xs))
in f
-- | For functions that should be printed uncurried.
uncurried =
TermStyle $ \l _ d ->
let
f [] = d
f xs =
d <> parens (hsep (punctuate comma (map (pPrintPrec l 0) xs)))
in f
-- | A helper function that deals with under- and oversaturated applications.
fixedArity :: Int -> TermStyle -> TermStyle
fixedArity arity style =
TermStyle $ \l p d ->
let
f xs
| length xs < arity = pPrintTerm curried l p (parens d) xs
| length xs > arity =
pPrintParen (p > 10) $
hsep (pPrintTerm style l 11 d ys:
map (pPrintPrec l 11) zs)
| otherwise = pPrintTerm style l p d xs
where
(ys, zs) = splitAt arity xs
in f
-- | A helper function that drops a certain number of arguments.
implicitArguments :: Int -> TermStyle -> TermStyle
implicitArguments n (TermStyle pp) =
TermStyle $ \l p d xs -> pp l p d (drop n xs)
-- | For prefix operators.
prefix =
fixedArity 1 $
TermStyle $ \l _ d [x] ->
d <> pPrintPrec l 11 x
-- | For postfix operators.
postfix =
fixedArity 1 $
TermStyle $ \l _ d [x] ->
pPrintPrec l 11 x <> d
-- | For infix operators.
infixStyle :: Int -> TermStyle
infixStyle pOp =
fixedArity 2 $
TermStyle $ \l p d [x, y] ->
pPrintParen (p > fromIntegral pOp) $
pPrintPrec l (fromIntegral pOp+1) x <+> d <+>
pPrintPrec l (fromIntegral pOp+1) y
-- | For tuples.
tupleStyle :: TermStyle
tupleStyle =
TermStyle $ \l _ _ xs ->
parens (hsep (punctuate comma (map (pPrintPrec l 0) xs)))