Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I cast from Integer to Fractional

Let's say I have the following Haskell type description:

divide_by_hundred :: Integer -> IO()
divide_by_hundred n = print(n/100)

Why is it that when I attempt to run this through ghc I get:

No instance for (Fractional Integer) arising from a use of `/'
Possible fix: add an instance declaration for (Fractional Integer)
In the first argument of `print', namely `(n / 100)'
In the expression: print (n / 100)
In an equation for `divide_by_hundred':
    divide_by_hundred n = print (n / 100)

By running :t (/) I get:

(/) :: Fractional a => a -> a -> a

which, to me, suggests that the (/) can take any Num that can be expressed as fractional (which I was under the impression should include Integer, though I am unsure as how to verify this), as long as both inputs to / are of the same type.

This is clearly not accurate. Why? And how would I write a simple function to divide an Integer by 100?

like image 578
Abraham P Avatar asked Mar 04 '14 14:03

Abraham P


1 Answers

Haskell likes to keep to the mathematically accepted meaning of operators. / should be the inverse of multiplication, but e.g. 5 / 4 * 4 couldn't possibly yield 5 for a Fractional Integer instance1.

So if you actually mean to do truncated integer division, the language forces you2 to make that explicit by using div or quot. OTOH, if you actually want the result as a fraction, you can use / fine, but you first need to convert to a type with a Fractional instance. For instance,

Prelude> let x = 5
Prelude> :t x
x :: Integer
Prelude> let y = fromIntegral x / 100
Prelude> y
5.0e-2
Prelude> :t y
y :: Double

Note that GHCi has selected the Double instance here because that's the simples default; you could also do

Prelude> let y' = fromIntegral x / 100 :: Rational
Prelude> y'
1 % 20

1Strictly speaking, this inverse identity doesn't quite hold for the Double instance either because of floating-point glitches, but there it's true at least approximately.

2Actually, not the language but the standard libraries. You could define

instance Fractional Integer where
  (/) = div

yourself, then your original code would work just fine. Only, it's a bad idea!

like image 160
leftaroundabout Avatar answered Sep 30 '22 20:09

leftaroundabout