Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inferred type is not general enough in Haskell

Tags:

haskell

I'm writing a program that takes in a list of elements (such list must take both integers and fractional numbers) and gives a list of cut sums:

  • first element of resulting list is the sum of the whole list
  • second is the sum of list without head
  • third is the sum of the list without head and second element
  • and so on.

My result so far is:

cuttingSum :: Num a => [a] -> [a]
cuttingSum l = 
 let         
  cuttingSum_iter [] res = reverse (res)
  cuttingSum_iter ll res =
  cuttingSum_iter (tail ll) ((foldl (+) 0 ll) :: res)
 in
  cuttingSum_iter l []


main = do
 print $ cuttingSum [1,2,3]

I'm getting error:

 ERROR "task9-02-1.hs":5 - Inferred type is not general enough
*** Expression    : foldl (+) 0 ll
*** Expected type : a
*** Inferred type : _26

I'm using Hugs as it's the task requirement, but ghci also shows some sort of similar error. What's the problem?

like image 805
vladfau Avatar asked Dec 20 '22 11:12

vladfau


1 Answers

The problem is simply a typo, you have foldl (+) 0 ll :: res instead of foldl (+) 0 ll : res, with only one :. This is because :: indicates the type of an expression. When you have

cuttingSum_iter ll res = cuttingSum (tail ll) ((foldl (+) 0 ll) :: res)

This is equivalent to

cuttingSum_iter ll res = cuttingSum (tail ll) ((foldl (+) 0 ll) :: b)

Because res as an argument and res as a type live in different namespaces. In the type namespace, any identifier beginning with a lower case letter is a type variable, and as we know the name of a variable doesn't matter to the compiler, only to the programmer. From this point, I'll refer to it as b to avoid confusion with the res argument.

Since you're telling the compiler that the expression foldl (+) 0 ll has the type b, it fails the type checking stage. The compiler can figure out that ll is at least a list, and using it in foldl (+) 0 means that it must contain Num elements, so foldl (+) 0 ll must have type Num a => a. This does not match with the type b, since b does not have the Num constraint. This is what leads to the error message you see of

ERROR "task9-02-1.hs":5 - Inferred type is not general enough

The inferred type is not general enough because the inferred type has the Num constraint.

In GHC, you'd instead get the error

Couldn't match type ‘t’ with ‘res’
  because type variable ‘res’ would escape its scope
This (rigid, skolem) type variable is bound by
  an expression type signature: res
  at <interactive>:13:57-79
Expected type: [res]
  Actual type: [t]
Relevant bindings include
  ll :: [t] (bound at <interactive>:13:21)
  cuttingSum_iter :: [t] -> [a] -> [a] (bound at <interactive>:12:5)
In the third argument of ‘foldl’, namely ‘ll’
In the second argument of ‘cuttingSum_iter’, namely
  ‘((foldl (+) 0 ll) :: res)’

To me, this one is a little more clear since it mentions the "type variable res" on the second line, and says it expected it to have [res] while expecting the type [t] where cuttingSum_iter has the type [t] -> [a] -> [a]. Seeing that it mentions "type variable res" and "Expected type: [res]", this at least points a little more towards what the problem was, although it still isn't immediately clear what is actually the problem.

like image 105
bheklilr Avatar answered Jan 14 '23 15:01

bheklilr