{-| Module  : FiniteCategories
Description : A simple typeclass for things to be pretty printed.
Copyright   : Guillaume Sabbagh 2021
License     : GPL-3
Maintainer  : guillaumesabbagh@protonmail.com
Stability   : experimental
Portability : portable

A simple typeclass for things to be pretty printed. Things should be pretty printable to be exported with graphviz.
-}
module IO.PrettyPrint
(
    PrettyPrintable(..),
    pprintFunction
)
where
    import Data.List  (intercalate)
    import Data.Set   (Set, toList)
    import Data.Map   (Map, keys, (!))
    import Data.Maybe
    import Data.Either
    import Data.Text  (Text, unpack)
    
    -- | The typeclass of things that can be pretty printed.

    class PrettyPrintable a where
        pprint :: a -> String
        
    instance (PrettyPrintable a) => PrettyPrintable [a] where
        pprint :: [a] -> String
pprint [a]
xs = String
"[" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
"," (a -> String
forall a. PrettyPrintable a => a -> String
pprint (a -> String) -> [a] -> [String]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [a]
xs) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"]"
        
    
    instance (PrettyPrintable a, PrettyPrintable b) => PrettyPrintable (a,b) where
        pprint :: (a, b) -> String
pprint (a
a,b
b) = String
"(" String -> String -> String
forall a. [a] -> [a] -> [a]
++ a -> String
forall a. PrettyPrintable a => a -> String
pprint a
a String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"," String -> String -> String
forall a. [a] -> [a] -> [a]
++ b -> String
forall a. PrettyPrintable a => a -> String
pprint b
b String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
")"
    
    instance (PrettyPrintable a, PrettyPrintable b, PrettyPrintable c) => PrettyPrintable (a,b,c) where
        pprint :: (a, b, c) -> String
pprint (a
a,b
b,c
c) = String
"(" String -> String -> String
forall a. [a] -> [a] -> [a]
++ a -> String
forall a. PrettyPrintable a => a -> String
pprint a
a String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"," String -> String -> String
forall a. [a] -> [a] -> [a]
++ b -> String
forall a. PrettyPrintable a => a -> String
pprint b
b String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"," String -> String -> String
forall a. [a] -> [a] -> [a]
++ c -> String
forall a. PrettyPrintable a => a -> String
pprint c
c String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
")"
        
    instance (PrettyPrintable a) => PrettyPrintable (Set a) where
        pprint :: Set a -> String
pprint Set a
xs = String
"{" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
"," (a -> String
forall a. PrettyPrintable a => a -> String
pprint (a -> String) -> [a] -> [String]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Set a -> [a]
forall a. Set a -> [a]
toList Set a
xs)) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"}"
        
    instance PrettyPrintable Int where
        pprint :: Int -> String
pprint = Int -> String
forall a. Show a => a -> String
show
        
    instance PrettyPrintable Double where
        pprint :: Double -> String
pprint = Double -> String
forall a. Show a => a -> String
show
        
    instance PrettyPrintable Char where
        pprint :: Char -> String
pprint = Char -> String
forall a. Show a => a -> String
show
        
    instance (Ord k, PrettyPrintable k, PrettyPrintable a) => PrettyPrintable (Map k a) where
        pprint :: Map k a -> String
pprint Map k a
m = String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
"\n" [k -> String
forall a. PrettyPrintable a => a -> String
pprint k
k String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"->" String -> String -> String
forall a. [a] -> [a] -> [a]
++a -> String
forall a. PrettyPrintable a => a -> String
pprint (Map k a
mMap k a -> k -> a
forall k a. Ord k => Map k a -> k -> a
!k
k)| k
k <- Map k a -> [k]
forall k a. Map k a -> [k]
keys Map k a
m]
        
    instance (PrettyPrintable a) => PrettyPrintable (Maybe a) where
        pprint :: Maybe a -> String
pprint Maybe a
Nothing = String
"Nothing"
        pprint (Just a
a) = a -> String
forall a. PrettyPrintable a => a -> String
pprint a
a
        
    instance (PrettyPrintable a, PrettyPrintable b) => PrettyPrintable (Either a b) where
        pprint :: Either a b -> String
pprint (Left a
x) = a -> String
forall a. PrettyPrintable a => a -> String
pprint a
x
        pprint (Right b
x) = b -> String
forall a. PrettyPrintable a => a -> String
pprint b
x
        
    instance PrettyPrintable Text where
        pprint :: Text -> String
pprint = Text -> String
unpack
    
    -- | Pretty print a function on a specific domain.

    pprintFunction :: (PrettyPrintable a, PrettyPrintable b) =>
                   (a -> b) -> [a] -> String
    pprintFunction :: forall a b.
(PrettyPrintable a, PrettyPrintable b) =>
(a -> b) -> [a] -> String
pprintFunction a -> b
f [a]
xs = String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
"\n" [a -> String
forall a. PrettyPrintable a => a -> String
pprint a
x String -> String -> String
forall a. [a] -> [a] -> [a]
++String
" -> " String -> String -> String
forall a. [a] -> [a] -> [a]
++ b -> String
forall a. PrettyPrintable a => a -> String
pprint (a -> b
f a
x) | a
x <- [a]
xs]