0

I got a data type "Cake"

*data Cake = EmptyBox | Food { name :: String
                                , flavors :: [Cake]} deriving( Read, Eq)*

instance Show Cake where
  show cake = prints cake where
   prints (Food name []) = name ++ "\n"

I want to print cakes like this (each cake got different flavors)

Cake1
  Chocolate
  Nutella
    Strawberry
Cake2
  Chocolate
  Vanilla
Cake3

But I got error, doesn't works! How can I do it?

4
  • 2
    Good, you are showing your code. But what error are you getting? Commented Nov 21, 2017 at 21:46
  • Couldn't match type ‘Char’ with ‘[Char]’ on "show cake = prints cake where" Commented Nov 21, 2017 at 21:48
  • You should avoid using show for pretty printing. There was a recent question that answered nearly this exact question though. Can you extrapolate from this? Commented Nov 21, 2017 at 22:35
  • 1
    If that doesn't help, you need to write an MCVE. Note that the "V" there is "Verifiable" -- write something we can run. Commented Nov 21, 2017 at 22:38

2 Answers 2

2

Since prints :: Cake -> String and flavors :: [Cake], we know

map prints flavors :: [String]

But this doesn't jive with the context in which it is used, since in

" " ++ expr

the " " is clearly a String and we therefore expect expr to be a String and not a [String].

To fix this, you should write or find a function which converts your [String] into a String in some way -- there are many candidate behaviors for this type, so you should decide what behavior you want and then find a way to achieve that behavior.

Sign up to request clarification or add additional context in comments.

Comments

0

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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.