views:

186

answers:

2

I have the following haskell code:

fac n = product [1..n]

taylor3s w0 f f' f'' t h = w1 : taylor3s w1 f f' f'' (t+h) h
  where hp i = h^i / fac i
        w1 = w0 + (hp 1) * f t w0 + (hp 2) * f' t w0 + (hp 3) * f'' t w0

taylor_results = take 4 $ taylor3s 1 f f' f'' 1 0.25
  where f   t x = t^4 - 4*x/t
        f'  t x = 4*t^3 - 4*(f t x)/t + 4*x/t^2
        f'' t x = 12*t^2 - 4*(f' t x)/t + 8*(f t x)/t^2 - 8*x/t^3

taylor_results is supposed to be a use case of taylor3s. However, there is something wrong with the number type inferencing. When I try to compile, this is the error I get:

practice.hs:93:26:
    Ambiguous type variable `a' in the constraints:
      `Integral a'
        arising from a use of `taylor3s' at practice.hs:93:26-51
      `Fractional a' arising from a use of `f' at practice.hs:93:37
    Possible cause: the monomorphism restriction applied to the following:
      taylor_results :: [a] (bound at practice.hs:93:0)
    Probable fix: give these definition(s) an explicit type signature
                  or use -XNoMonomorphismRestriction

Can someone help me with understanding what the problem is?

A: 

It appears that Haskell is inferring the return of taylor3s as being an Integral type, but then the fact that the subfunctions f etc are inferred as dealing with Fractional types violates that inference.

Perhaps by explicitly telling Haskell the taylor3s return type might help.

Amber
+8  A: 

Since you're mixing operations that are only available on integrals and operations that are only available on fractionals (specifically you use ^ of which the second operand must be integral - use ** if you intend for both operands to have the same Floating type), haskell infers that all arguments and the result of taylor3s have the type Fractional a, Integral a => a. This is not a type error, since theoretically such a type could exist, but it's most likely not what you want because in practice such a type does not exist.

The reason that you get a type error anyway is that the inferred type of taylor_results is consequently also Fractional a, Integral a => a which is polymorphic and thus violates the monomorphism restriction.

If you would explicitly declare taylor_results as taylor_results :: Fractional a, Integral a => a or disable the monomorphism restriction, the whole thing would compile, but be impossible to use (without defining a type that actually instantiates Integral and Fractional, which would be nonsense).

Note that if you fix this (for example by replacing ^ with **) the type of taylor_results will still be polymorphic (it will be inferred as taylor_results :: (Floating a, Enum a) => [a], which is actually sensible), so you will still run into the monomorphism restriction. So you still need to either turn the restriction off, explicitly declare the type of taylor_results to be polymorphic or explicitly declare the type of taylor_results to be a specific type that instantiates Floating and Enum (e.g. Double). Note that unless you do the latter, taylor_results will be recalculated each time you use it (which is why the monomorphism restriction exists).

Note that if you fix this (for example by replacing ^ with **) the most general type of taylor_results will be (Floating a, Enum a) => [a], however the type you get (unless you disable the monomorphism restriction) will be [Double]. If you don't want doubles, you either have to explicitly declare taylor_results to be of another type (which instantiates Floating and Enum) or to be polymorphic. Note that if you declare it to be polymorphic, taylor_results will be recalculated each time you use it (which is why the monomorphism restriction exists).

sepp2k
+1 For the ^/** answer. However Haskell will infer taylor_result as taylor_results :: [Double] due to the use of 0.25 ( i.e a Double type ) so there won't be any monomorphic restrictions
zebrabox
@zebrabox: The type of `0.25` is `0.25 :: (Fractional t) => t`, not Double. And the inferred type of taylor_results most definitely is `(Floating a, Enum a) => [a]` after replacing `^` with `**`. I actually checked this in ghci.
sepp2k
@zebrabox: Gah, I have to correct myself. *Without the monomorphism restriction* the inferred type will be `(Floating a, Enum a) => [a]`. However with the restriction enabled the type will just be specialized to `[Double]` without causing an error because of haskell's defaulting rules regarding Numbers.
sepp2k