JohnnyPire
JohnnyPire

Reputation: 119

instance Show haskell

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?

Upvotes: 0

Views: 1117

Answers (2)

Adam Smith
Adam Smith

Reputation: 54233

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

Upvotes: 0

Daniel Wagner
Daniel Wagner

Reputation: 153172

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.

Upvotes: 2

Related Questions