module Data.Tabular (
Rows(..)
, Row(..)
, Cell(..)
, Tabular(..)
, readTabular
, writeTabular
) where
import Control.Monad (ap, liftM)
import Data.List (intercalate)
import Data.List.Split (splitOn)
newtype Rows = Rows {unRows :: [Row]}
deriving Eq
instance Read Rows where
readsPrec _ = return . (, "") . Rows . map read . lines
instance Show Rows where
show = unlines . map show . unRows
newtype Row = Row {unRow :: [String]}
deriving Eq
instance Read Row where
readsPrec _ = return . (, "") . Row . splitOn tab
instance Show Row where
show = intercalate tab . unRow
tab :: String
tab = "\t"
class Tabular a where
toRow :: a -> Row
fromRow :: Row -> a
withHeader :: [a] -> Rows
withHeader = Rows . (Row ["<<UNDEFINED HEADER>>"] :) . map toRow
checkHeader :: Rows -> [a]
checkHeader = map fromRow . tail . unRows
instance (Cell a, Monad ((->) [[a]])) => Tabular [a] where
toRow = Row . map toCell
fromRow = map fromCell . unRow
withHeader = Rows . ap ((:) . Row . map (const "<<UNDEFINED COLUMN>>") . head) (map toRow)
instance (Cell a, Cell b) => Tabular (a, b) where
toRow (x, y) = Row [toCell x, toCell y]
fromRow (Row [x, y]) = (fromCell x, fromCell y)
fromRow (Row t) = error $ "not a doublet" ++ show t
instance (Cell a, Cell b, Cell c) => Tabular (a, b, c) where
toRow (x, y, z) = Row [toCell x, toCell y, toCell z]
fromRow (Row [x, y, z]) = (fromCell x, fromCell y, fromCell z)
fromRow (Row t) = error $ "not a triplet: " ++ show t
instance (Cell a, Cell b, Cell c, Cell d) => Tabular (a, b, c, d) where
toRow (x, y, z, w) = Row [toCell x, toCell y, toCell z, toCell w]
fromRow (Row [x, y, z, w]) = (fromCell x, fromCell y, fromCell z, fromCell w)
fromRow (Row t) = error $ "not a quadruplet: " ++ show t
class Cell a where
toCell :: a -> String
fromCell :: String -> a
instance (Read a, Show a) => Cell a where
fromCell = read
toCell = show
readTabular :: Tabular a
=> FilePath
-> IO [a]
readTabular = liftM (checkHeader . read) . readFile
writeTabular :: Tabular a
=> FilePath
-> [a]
-> IO ()
writeTabular = (. (show . withHeader)) . writeFile