Search code examples
haskelltreelet

Function inside let not Num


I have these

data Fruit = Peach | Apple | Pear | Lemon | Fig deriving (Show,Eq)
data FTree = Bud | Split FTree FTree | Flat Fruit FTree deriving (Show,Eq)

and this meant to count the number of occurrences of an inputted fruit type

ftreeFOccurs cft ft =
  let ftFO Bud = 0
      ftFO (Flat frt ft) = if (frt == cft) then (1 + (ftFO ft)) else (ftFO ft)
      ftFO (Split ft1 ft2) = (Split (ftFO ft1) (ftFO ft2))
  in ftFO ft

and here would be a typical tree

Split (Split Bud Bud) (Flat Fig (Flat Lemon (Flat Apple Bud)))

But when I submit ftreeFOccurs I get this error

No instance for (Num FTree) arising from the literal `0'
    * In the expression: 0
      In an equation for `ftFO': ftFO Bud = 0

A similar function, however,

ftreeHeight Bud = 0
ftreeHeight (Flat frt ft) = 1 + ftreeHeight ft
ftreeHeight (Split ft1 ft2) = deeper (1 + ftreeHeight ft1) (1 + ftreeHeight ft2)
                              where deeper t1 t2 = if (t1 >= t2) then t1 else t2

works. This is a translation of an SML problem from The Little MLer, where the occurs function has a 2-tuple parameter with the fruit and the tree carried through the recursions ... which doesn't seem like the Haskell way. But then I'm not sure why having a function in a let makes this difference.


Solution

  • Put some types on your functions so that Haskell can give you better hints about where you went wrong. Without types, it will make assumptions about what you meant until it reaches a contradiction, and you won't know which assumption was wrong.

    In this case, the confusion is that sometimes ftFO returns a number, and sometimes it returns an FTree. This isn't want you meant, but it's technically allowed if Haskell assumes that FTree can be understood as a number. So Haskell carries on with that idea for a while until it discovers that nobody has said how to interpret FTree as a number.