This is the Monomorphism restriction at work. The solution is to add a type signature:
new_product :: (Foldable t, Num b) => t b -> b
new_product = foldr (*) 1
Essentially, the problem here is that unless you are in GHCi (where this is disabled) Haskell refuses to infer a polymorphic type signature unless you explicitly have variables for the function. As a concrete example:
f x = ... -- `f` can infer polymorphic type (in `x`)
f = \x -> ... -- `f` infers a monomorphic type
In your case, f
is new_product
and x
is xs
. When you have the point-free style, Haskell attempts to infer a monomorphic signature for new_product
and fails because it can't figure out which Foldable
instance to choose (based on foldr
). On the other hand, when you include the xs
, Haskell is no longer bound to infer a monomorphic signature, hence everything works.
There is reason to this madness: the point is that when you write something like f = ...
it is natural to assume that f
only gets evaluated once. Yet, unless we force f
to be monomorphic, that isn't necessarily the case.
To use an example related to your function: suppose that I infer that p = num_product [1..1000]
has type Num a => a
(the most general type in this case), then using p :: Int
and p :: Integer
will cause us to evaluate p
at least twice.
Haskell has therefore decided not to generalize top-level bindings: you only infer polymorphic signatures for functions that have their variables explicit (ie. on the left hand side of the equal). That said, if you wish to explicitly write a polymorphic type signature, you are free to do so.