module Problem2b where type Doc = [String] ($$) :: Doc -> Doc -> Doc ($$) = (++) (<>) :: Doc -> Doc -> Doc [] <> ys = ys xs <> [] = xs [x] <> (y : ys) = (x ++ y) : map (replicate (length x) ' ' ++) ys (x : xs) <> ys = x : (xs <> ys) text :: String -> Doc text s = [s] render :: Doc -> String render xs = unlines xs empty :: Doc empty = [] -- Answer to problem 2a: -- indent can be defined in terms of (<>) and text indent :: Int -> Doc -> Doc indent n xs = text (replicate n ' ') <> xs -- (<+>) can be defined in terms of (<>) and indent. (<+>) :: Doc -> Doc -> Doc xs <+> ys = xs <> indent 1 ys -- Alternatively (inlining the definition of indent) -- xs <+> ys = xs <> text " " <> ys -- Note that empty and text "" are different: true1 = render (text "A" $$ empty $$ text "B") == "A\nB\n" true2 = render (text "A" $$ text "" $$ text "B") == "A\n\nB\n"