repa-array-4.2.2.1: Data/Repa/Nice/Tabulate.hs
{-# LANGUAGE UndecidableInstances #-}
module Data.Repa.Nice.Tabulate
( tab
, tabulate
, Str (..)
, Tok (..))
where
import Data.Repa.Nice.Present as A
import Data.Repa.Nice.Display as A
import Data.List as L
import qualified Data.Text as T
import Data.Text (Text)
import Data.Maybe
-- | Print a nested value to the console in tabular form.
--
-- The first two layers of nesting are displayed as rows and columns.
-- Numeric data is right-justified, while the rest is left-justified.
--
-- @
-- > tab [[10, 20, 302], [40, 50], [60, 7001, 80, 90 :: Int]]
-- 10 20 302
-- 40 50
-- 60 7001 80 90
-- @
--
-- Deeper layers of nesting are preserved in the output:
--
-- @
-- > tab [[[10], [20, 21]], [[30, 31], [40, 41, 41], [50 :: Int]]]
-- [10] [20,21]
-- [30,31] [40,41,41] [50]
-- @
--
-- By default, strings are printed as lists of characters:
--
-- @
-- > tab [[("red", 10), ("green", 20), ("blue", 30)], [("grey", 40), ("white", 50 :: Int)]]
-- ([\'r\',\'e\',\'d\'],10) ([\'g\',\'r\',\'e\',\'e\',\'n\'],20) ([\'b\',\'l\',\'u\',\'e\'],30)
-- ([\'g\',\'r\',\'e\',\'y\'],40) ([\'w\',\'h\',\'i\',\'t\',\'e\'],50)
-- @
--
-- If you want double-quotes then wrap the strings with a @Str@ constructor:
--
-- @
-- > tab [[(Str "red", 10), (Str "green", 20), (Str "blue", 30)], [(Str "grey", 40), (Str "white", 50 :: Int)]]
-- ("red",10) ("green",20) ("blue",30)
-- ("grey",40) ("white",50)
-- @
--
-- If you don't want any quotes then wrap them with a @Tok@ constructor:
--
-- @
-- > tab [[(Tok "red", 10), (Tok "green", 20), (Tok "blue", 30)], [(Tok "grey", 40), (Tok "white", 50 :: Int)]]
-- (red,10) (green,20) (blue,30)
-- (grey,40) (white,50)
-- @
--
tab :: Presentable a => a -> IO ()
tab val
= putStrLn $ T.unpack $ tabulate val
-- | Display a nested value in tabular form.
--
tabulate :: Presentable a => a -> Text
tabulate xx
= let pp = present xx
in case depth pp of
0 -> flatten pp
1 -> let Just pss = strip1 pp
in tabulate1 $ map flatten pss
_ -> let Just pss = strip2 pp
in tabulate2 $ map (map flatten) pss
tabulate1 :: [Text] -> Text
tabulate1 strs
= let d = mconcat $ map takeDisplay strs
in T.intercalate (T.pack "\n")
$ L.map (display d) strs
tabulate2 :: [[Text]] -> Text
tabulate2 strss
= let
-- Decide how to display a single column.
displayOfCol c
= mconcat
$ mapMaybe (\line -> if c >= length line
then Nothing
else Just (takeDisplay (line !! c)))
$ strss
-- How many columns we have.
nCols = maximum $ L.map L.length strss
-- Decide how to display all the columns.
displays = L.map displayOfCol [0.. nCols - 1]
makeLine line
= T.intercalate (T.pack " ")
$ L.zipWith display displays line
in T.intercalate (T.pack "\n")
$ L.map makeLine strss