{-| Module  : FiniteCategories
Description : A simple typeclass for things to be pretty printed.
Copyright   : Guillaume Sabbagh 2022
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.
Different objects should be pretty printed into different strings or the graphviz export might be wrong.
-}
module Math.IO.PrettyPrint
(
    PrettyPrint(..),
    pprintFunction
)
where
    import              Data.List  (intercalate)
    import qualified    Data.Set                                            as Set
    import qualified    Data.WeakSet                                        as WSet
    import qualified    Data.WeakMap                                        as WMap
    import qualified    Math.PureSet                                        as PSet
    import qualified    Data.Text                                           as Text
    
    import              Numeric.Natural
    
    -- | The typeclass of things that can be pretty printed.

    class PrettyPrint a where
        pprint :: a -> String
        
    instance (PrettyPrint a) => PrettyPrint [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. PrettyPrint 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 (PrettyPrint a, PrettyPrint b) => PrettyPrint (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. PrettyPrint 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. PrettyPrint a => a -> String
pprint b
b String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
")"
    
    instance (PrettyPrint a, PrettyPrint b, PrettyPrint c) => PrettyPrint (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. PrettyPrint 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. PrettyPrint 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. PrettyPrint a => a -> String
pprint c
c String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
")"
        
    instance (PrettyPrint a) => PrettyPrint (Set.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. PrettyPrint 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]
Set.toList Set a
xs)) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"}"
        
    instance (PrettyPrint a, Eq a) => PrettyPrint (WSet.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. PrettyPrint 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. Eq a => Set a -> [a]
WSet.setToList Set a
xs)) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"}"
        
    instance (PrettyPrint a, Eq a, PrettyPrint b, Eq b) => PrettyPrint (WMap.Map a b) where
        pprint :: Map a b -> String
pprint Map a b
m = String
"{" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
"," ((\(a
k,b
v) -> (a -> String
forall a. PrettyPrint a => a -> String
pprint a
k) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"->" String -> String -> String
forall a. [a] -> [a] -> [a]
++ (b -> String
forall a. PrettyPrint a => a -> String
pprint b
v)) ((a, b) -> String) -> [(a, b)] -> [String]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Map a b -> [(a, b)]
forall k v. Eq k => Map k v -> AssociationList k v
WMap.mapToList Map a b
m)) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"}"
        
    instance PrettyPrint PSet.PureSet where
        pprint :: PureSet -> String
pprint = PureSet -> String
PSet.formatPureSet
        
    instance PrettyPrint Int where
        pprint :: Int -> String
pprint = Int -> String
forall a. Show a => a -> String
show
        
    instance PrettyPrint Double where
        pprint :: Double -> String
pprint = Double -> String
forall a. Show a => a -> String
show
        
    instance PrettyPrint Natural where
        pprint :: Natural -> String
pprint = Natural -> String
forall a. Show a => a -> String
show
        
    instance PrettyPrint Char where
        pprint :: Char -> String
pprint = (Char -> String -> String
forall a. a -> [a] -> [a]
:[])
    
    instance PrettyPrint Text.Text where
        pprint :: Text -> String
pprint = Text -> String
Text.unpack
    
    -- | Pretty print a function on a specific domain.

    pprintFunction :: (PrettyPrint a, PrettyPrint b) =>
                   (a -> b) -> [a] -> String
    pprintFunction :: forall a b.
(PrettyPrint a, PrettyPrint 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. PrettyPrint 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. PrettyPrint a => a -> String
pprint (a -> b
f a
x) | a
x <- [a]
xs]