Haskell: Define product with foldr

前端 未结 1 1487
悲&欢浪女
悲&欢浪女 2021-01-23 06:40

I\'m trying to define product with foldr:

I could do it with:

new_product xs = foldr (*) 1 xs

but not:

1条回答
  •  一整个雨季
    2021-01-23 07:22

    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.

    0 讨论(0)
提交回复
热议问题