For test data, I used:
cake1 = Food{name="Cake1"
,flavors=[Food{name="Chocolate"
,flavors=[]}
,Food{name="Nutella"
,flavors=[Food{name="Strawberry"
,flavors=[]}]}]}
cake2 = Food{name="Cake2"
,flavors=[Food{name="Chocolate"
,flavors=[]}
,Food{name="Vanilla"
,flavors=[]}]}
cake3 = Food{name="Cake3"
,flavors=[]}
and wrote Show Cake as unlines composed with a function that has type Cake -> [String]
instance Show Cake where
show = unlines . prints where
prints :: Cake -> [String]
prints EmptyBox = []
prints (Food s []) = [s] -- a Food with no subflavors
prints (Food s fs) = s:concatMap (map (" "++) . prints) fs
That last line handles the general case of a Food with name s and flavors fs by mapping prints over fs, then mapping (" "++) over each sublist in that map, and concat'ing them together.
(" "++) :: String -> String
map (" "++) :: [String] -> [String]
map (" "++) . prints :: Cake -> [String]
map (map (" "++) . prints) :: [Cake] -> [[String]]
concat . map (map (" "++) . prints) :: [Cake] -> [String]
concatMap = concat . map
concatMap (map (" "++) . prints) :: [Cake] -> [String]
Each successive level of flavors adds an extra level of indentation (that's what the (" "++) is for). We can test it:
TestModule> putStrLn $ concatMap show [cake1, cake2, cake3]
Cake1
Chocolate
Nutella
Strawberry
Cake2
Chocolate
Vanilla
Cake3
showfor pretty printing. There was a recent question that answered nearly this exact question though. Can you extrapolate from this?