import Data.List (groupBy, intersperse, mapAccumL, sortBy) import Data.Ord (comparing) import Data.Function (on) import Control.Arrow ((&&&)) -- Strings derived from integers, -- and split into [(initial string, final character)] tuples. xs :: [(String, Char)] xs = (init &&& last) . show <$> [ 12, 127, 28, 42, 39, 113, 42, 18, 44, 118, 44, 37, 113, 124, 37, 48, 127, 36, 29, 31, 125, 139, 131, 115, 105, 132, 104, 123, 35, 113, 122, 42, 117, 119, 58, 109, 23, 105, 63, 27, 44, 105, 99, 41, 128, 121, 116, 125, 32, 61, 37, 127, 29, 113, 121, 58, 114, 126, 53, 114, 96, 25, 109, 7, 31, 141, 46, 13, 27, 43, 117, 116, 27, 7, 68, 40, 31, 115, 124, 42, 128, 52, 71, 118, 117, 38, 27, 106, 33, 117, 116, 111, 40, 119, 47, 105, 57, 122, 109, 124, 115, 43, 120, 43, 27, 27, 18, 28, 48, 125, 107, 114, 34, 133, 45, 120, 30, 127, 31, 116, 146 ] -- Re-reading the initial strings as Ints -- (empty strings read as 0), ns :: [(Int, Char)] ns = (\x -> let s = fst x in ( if null s then 0 else (read s :: Int) , snd x)) <$> xs -- and sorting and grouping by these initial Ints, -- interpreting them as data-collection bins. bins :: [[(Int, Char)]] bins = groupBy (on (==) fst) (sortBy (mappend (comparing fst) (comparing snd)) ns) -- Forming bars by the ordered accumulation of final characters in each bin, bars :: [(Int, String)] bars = (fst . head &&& fmap snd) <$> bins -- and obtaining a complete series, with empty bar strings -- interpolated for any missing integers. series :: [(Int, String)] series = (concat . snd) $ mapAccumL (\a x -> let n = fst x in if a == n then (a + 1, [x]) else (n + 1, ((\i -> (i, "")) <$> [a .. (n - 1)]) ++ [x])) 1 bars -- Assembling the series as a list of strings with right-justified indices, justifyRight :: Int -> Char -> String -> String justifyRight n c s = drop (length s) (replicate n c ++ s) plotLines :: [String] plotLines = foldr (\x a -> (justifyRight 2 ' ' (show (fst x)) ++ " | " ++ intersperse ' ' (snd x)) : a) [] series -- and passing these over to IO as a single newline-delimited string. main :: IO () main = putStrLn $ unlines plotLines