tags:

views:

116

answers:

1

I'd like to divide two Int values in Haskell and obtain the result as a Float. I tried doing it like this:

foo :: Int -> Int -> Float
foo a b = fromRational $ a % b

but GHC (version 6.12.1) tells me "Couldn't match expected type 'Integer' against inferred type 'Int'" regarding the a in the expression.

I understand why: the fromRational call requires (%) to produce a Ratio Integer, so the operands need to be of type Integer rather than Int. But the values I'm dividing are nowhere near the Int range limit, so using an arbitrary-precision bignum type seems like overkill.

What's the right way to do this? Should I just call toInteger on my operands, or is there a better approach (maybe one not involving (%) and ratios) that I don't know about?

+3  A: 

You have to convert the operands to floats first and then divide, otherwise you'll perform an integer division (no decimal places).

Laconic solution (requires Data.Function)

foo = (/) `on` fromIntegral

which is short for

foo a b = (fromIntegral a) / (fromIntegral b)

with

foo :: Int -> Int -> Float
Dario
Thanks, that makes sense. I'd wondered if I could convert to `Float` first, but somehow managed to overlook `fromIntegral` while browsing through the docs for all the functions in the various numeric classes. (I don't think the other approach would've done integer division losing decimal places as you alluded to, though: I was making a `Rational` from the integers, which doesn't lose precision.)
Wyzard
@Wyzard: You were not making a Rational from the integers. You were treating the result of the operator *as* as a Rational, when in fact it was not. Look at the type signature for `fromRational`: the argument is a Rational, while `Ratio Int` and `Ratio Integer` are both different types. You may have intended `toRational`.
Chuck
@Chuck: `Rational` is an alias for `Ratio Integer`, and `(%)` returns a `Ratio` of whatever type its operands are, so applying it to two `Integer` should produce a `Rational` (unless I'm misunderstanding). My problem was that I was giving it `Int` and producing `Ratio Int` (which is indeed *not* a `Rational`).
Wyzard
@Wyzard: You can convert here using `fromIntegral` again ... It's quite generic.
Dario