2
votes

I'm trying to define product with foldr:

I could do it with:

new_product xs = foldr (*) 1 xs

but not:

new_product = foldr (*) 1

or:

new_product = \xs -> foldr (*) 1 xs

Both definition produce the same error:

No instance for (Foldable t0) arising from a use of ‘folder’

The type variable ‘t0’ is ambiguous

Relevant bindings include

new_product :: t0 Integer -> Integer

Is it some kind of type error?

How could I fix it?

1
The claim "this question is already answered by 'What is the monomorphism restriction'?" is simply false and degrading to the user.Michael

1 Answers

3
votes

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.