qazwsx
qazwsx

Reputation: 26918

How to understand error messages for "1.2 % 3.4" for Haskell?

How to understand error messages for "1.2 % 3.4" for Haskell?

Prelude> :m +Data.Ratio
Prelude Data.Ratio> 4.3 % 1.2

<interactive>:11:1:
    No instance for (Show a0) arising from a use of ‘print’
    The type variable ‘a0’ is ambiguous
    Note: there are several potential instances:
      instance Show Double -- Defined in ‘GHC.Float’
      instance Show Float -- Defined in ‘GHC.Float’
      instance (Integral a, Show a) => Show (Ratio a)
        -- Defined in ‘GHC.Real’
      ...plus 23 others
    In a stmt of an interactive GHCi command: print it
Prelude Data.Ratio> 

Upvotes: 3

Views: 69

Answers (1)

&#216;rjan Johansen
&#216;rjan Johansen

Reputation: 18189

This type error message is a little unfriendly, me thinks.

What is actually happening here is that your expression has type

Prelude Data.Ratio> :t 4.3 % 1.2
4.3 % 1.2 :: (Integral a, Fractional a) => Ratio a

Integral a means your type a has to be integer-like, while Fractional a means that it has to be floating-point or rational-like. There are no types in standard Haskell which are both.

When evaluating this expression in order to print it, GHCi first infers its type, with the additional restriction that it needs to printable:

(Integral a, Fractional a, Show a) => Ratio a

Now since this is still too ambiguous to evaluate, GHCi tries defaulting a to either Integer or Double. But neither of them fits here, each is a member of just one of the classes Integral and Fractional.

Then, after failing at defaulting, GHCi gives an error message that tells you one of the constraints it was failing to satisfy. And particularly confusingly, it happens to choose the one which has nothing to do with why it failed...

Anyway, to fix your problem: % is not the function to divide two rationals, it is the function to construct a rational from an integer-like numerator and denominator. To divide them instead, use

4.3 / 1.2 :: Rational

The :: Rational tells GHCi that you want a rational (rather than the default Double it would otherwise choose), and floating-point notation does work to make a Rational - it is one of the features the Fractional typeclass provides.

Upvotes: 5

Related Questions