Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

problems with Haskell's Number Types

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?

like image 340
soundly_typed Avatar asked May 15 '10 07:05

soundly_typed


People also ask

What is the difference between int and integer in Haskell?

What's the difference between Integer and Int ? Integer can represent arbitrarily large integers, up to using all of the storage on your machine. Int can only represent integers in a finite range.

What is NUM Haskell?

Num is a typeclass — a group of types — which includes all types which are regarded as numbers. The (Num a) => part of the signature restricts a to number types – or, in Haskell terminology, instances of Num .

What does fromIntegral do in Haskell?

The workhorse for converting from integral types is fromIntegral , which will convert from any Integral type into any Num eric type (which includes Int , Integer , Rational , and Double ): fromIntegral :: (Num b, Integral a) => a -> b.

What is a Typeclass in Haskell?

Type Classes are a language mechanism in Haskell designed to support general overloading in a principled way. They address each of the concerns raised above. They provide concise types to describe overloaded functions, so there is no expo- nential blow-up in the number of versions of an overloaded function.


1 Answers

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).

like image 118
sepp2k Avatar answered Oct 06 '22 08:10

sepp2k