module Problem2d where
-- We just show how to solve the problem in the shallow
-- embedding. The same solution works for the deep embedding
-- by moving the code into the run function.
type Doc = Int -> [String]
ind :: Int -> [String] -> [String]
ind i = map (replicate i ' ' ++)
($$) :: Doc -> Doc -> Doc
(f $$ g) w = f w ++ g w
text :: String -> Doc
text s _ = [s]
empty :: Doc
empty _ = []
-- An interesting question is how to distribute the width
-- between the arguments to (<>). Here we choose to let
-- the first argument take as much space as it wants.
(<>) :: Doc -> Doc -> Doc
(f <> g) w = hcat (f w) g
where
hcat [] g = g w
hcat [x] g = case g (w - i) of
[] -> [x]
y : ys -> (x ++ y) : ind i ys
where
i = length x
hcat (x : xs) g = x : hcat xs g
cat :: Doc -> Doc -> Doc
cat f g w
| width tryH > w = (f $$ g) w
| otherwise = tryH
where
tryH = (f <> g) w
width [] = 0
width xs = maximum $ map length xs
render :: Int -> Doc -> String
render w f = unlines (f w)
-- Derived combinators
indent :: Int -> Doc -> Doc
indent i f = text (replicate i ' ') <> f
(<+>) :: Doc -> Doc -> Doc
f <+> g = f <> indent 1 g