Wireless
Wireless

Reputation: 107

Haskell Custom Show Instance

I've got a question, still working on the genealogy tree, here's what I've got so far (Sorry for the Portuguese words xD):

data Familia = Node String [Familia]

instance Show Familia where
  show (Node a b) = show a ++ "\n\t" ++ show b
raiz :: String -> Familia
raiz n = (Node n [])

juntar :: String -> String -> Familia -> Familia
juntar a b (Node c l) 
        | b == c = (Node c (l ++ [raiz a]))
        | otherwise = (Node c (juntarAux a b l))

juntarAux :: String -> String -> [Familia] -> [Familia]
juntarAux a b [] = []
juntarAux a b [(Node x l)]
        | x == b = [(juntar a b (Node x l))]
        | otherwise = [(Node x (juntarAux a b l))]
juntarAux a b ((Node x l):xs)
        | x == b = (juntar a b (Node x l)):xs
        | otherwise = (Node x l):(juntarAux a b xs)

This is working the way I want it to, the thing is, this is my current output:

*Main> let f = raiz "Bob"
*Main> let g = juntar "John" "Bob" f
*Main> g
"Bob"
    ["John"
    []]

And what I want is, to print it like so:

Bob
    John
         Ruth
    Hank

So, the Root of the family is Bob, Bob's son is John and Hank, John has a daughter called Ruth.

I've tried doing it several ways with stuff I saw in other posts, but this is the latest try:

instance Show Familia where
  show (Node a b) = show a ++ "\n\t" ++ (unlines $ map (unwords . map show) b)

This gives me the following error:

t4.hs:14:77:
Couldn't match type ‘Familia’ with ‘[a0]’
Expected type: [[a0]]
  Actual type: [Familia]
In the second argument of ‘map’, namely ‘b’
In the second argument of ‘($)’, namely
  ‘map (unwords . map show) b’

Any ideas? Thanks in advance! :D

Upvotes: 0

Views: 895

Answers (1)

Fyodor Soikin
Fyodor Soikin

Reputation: 80744

The expression map show is a function that expects an argument of type [a] - because map takes a function and a list.

Therefore, the expression (unwords . map show) is also a function that expects an argument of type [a].

Therefore, the expression map (unwords . map show) is a function that expects an argument of type [[a]] - it expects a list, each element of which is also a list, because it must be an acceptable argument for function (unwords . map show).

Therefore, in the expression map (unwords . map show) b, the last argument b must be of type [[a]] for some a.

But from the pattern Node a b, it follows that b is of type [Familia] - which is incompatible with [[a]]. This is what the compiler is telling you in the error message.

When you find yourself confused with types of nested functions, it is usually a good idea to pull them all apart, give a name (and maybe a type) to each piece. That will allow you to see where the mistake is.

instance Show Familia where
   show (Node a b) = show a ++ "\n\t" ++ concatSubFamilias 
      where
         showSubFamilias :: [String]
         showSubFamilias = map show b

         concatSubFamilias :: String
         concatSubFamilias = unlines showSubFamilias

Note that the above solution won't give you the result you're after, because it doesn't insert indentation before nested Familias. I leave that as an exercise for the reader.

Upvotes: 1

Related Questions