# Is writing arithmetic functions to allow "type coercion" a good idea?

Let's say I want to write a function to compute factorials of nonnegative integers. I could write something like this:

``````fact :: Num a => Int -> a
fact n = fromInteger(product [1..n])
``````

(Let's not concern ourselves with negative values of n at the moment, as that isn't what my question is about.) If I write the function this way, it means that if I want to turn around and use it in an expression like

``````myExp x :: Double -> Double
myExp x = sum(map (\k -> x^k/fact(k)) [0..9])
``````

directly, without bothering with converting the integer to a double.

Is there any reason not to do this? Am I losing something desirable that the type system would do for me?

I suspect that the only reason the arithmetic operators have restrictive types (e.g.

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

so that `3.0 / (1 :: Int)` is an error) is that the type system wouldn't be able to express things like "use the type of either operand, whichever is bigger." Am I correct?

In your example, calling `fromInteger` is redundant. You might as well have written:

``````fact :: (Num a, Enum a) => a -> a
fact n = product [1..n]
``````

because `product` already has type `Num a => [a] -> a` (it's now also polymorphic on `Foldable` types instead of being specific for lists but let us forget it for the moment), and the built-in `[1..n]` syntax uses the `Enum` typeclass under the hood .

What your invocation of `fromInteger` does is to monomorphise the result of product to `Integer`, since that's the type of the argument of `fromInteger`, which is a `Num` instance as well so it works. Then, `fromInteger` returns again an arbitrary `Num`. So this is a redundant round-trip where you could have as well just used the generic `Num` value returned by `product`.

Then, in the other function, everything works out since `Double` is also a `Num` instance.

So in this case you are not loosing nor gaining nothing. What's the point of the hierachy of type classes of numeric types, then?

If you wrote your example in a language like C, that would have been an automatic promotion, which is fine (in this case, not always, as C programmers know). Instead, in Haskell, you write code as if you were exploiting promotions, without ever having promotions at all, since the code is monomorphised at the invocation site and operations are performed on the desired type from the start: the `fact` function (without the `fromInteger` redundant call) works on `Double`s if its called to return a `Double`, it does not work on `Integer`s just to promote the `Integer` result back to `Double`.

On the other hand, conversions on the other direction, i.e. coercions, have to be forbidden. This happens if you have a function returning a `Fractional` (e.g. a `Double`) and you pass it to a function that wants a `Num`. You would obtain a type mismatch and this avoids unexpected information loss.

• The definition of `fact` you give above doesn't compile for me, which I expected, since at least in my environment `\n -> product [1..n]` has type `a -> a` (with constraints on `a`), which could only specialize to `Int -> Int`, not `Int -> a`, Are you using a different version of Haskell? I'm using GHC 8. Commented Feb 27, 2018 at 15:05
• Yes, it was a typo in the type signature. I've updated it, also with the missing `Enum a` constraint that comes from the use of the `[1..n]` list syntax. Commented Mar 1, 2018 at 5:26
• If I understand correctly, I think the middle of your answer is based on the premise that Double satisfies the constraints for the argument (and hence the result) of `fact`, but with the Enum constraint that's not true. Commented Mar 1, 2018 at 13:50
• If the above comment wasn't clear, my problem is that the example in my question won't compile using your version of `fact`; it needs a `fromIntegral` somewhere or perhaps some other method of making the types match so the arithmetic can be done. Commented Mar 13, 2018 at 12:42
• Yes you need `fromIntegral` to fit my version of `fact` in your example Commented Mar 22, 2018 at 2:26

First off, the code you've given:

``````fact :: Num a => Int -> a
fact n = fromInteger (product [1..n])
``````

doesn't type check. So, that's a pretty good reason right there not to write the function that way. The problem is that `n` is of type `Int`, so `product [1..n]` is also of type `Int`, but `fromInteger` expects an `Integer`, not an `Int`.

You could replace `fromInteger` with `fromIntegral`, but you shouldn't. Observe:

``````fact1 :: Num a => Int -> a
fact1 n = fromIntegral (product [1..n])
``````

and in GHCi:

``````> fact1 10
3628800
> fact1 100
0
> fact1 100 :: Double
0.0
> fact1 100 :: Integer
0
>
``````

In comparison, a sensible implementation of a polymorphic `fact` might look like:

``````fact2 :: (Integral n, Num a, Enum a) => n -> a
-- OR:  fact2 :: (Num a, Enum a) => Int -> a
fact2 n = product [1..fromIntegral n]
``````

and:

``````> fact2 100 :: Int
0    -- correct value in light of `Int` overflow
> fact2 100 :: Integer
9332...long number here...000  -- correct for infinite-precision integer
> fact2 100 :: Double
9.33262154439441e157   -- right again, when working with `Double`s
>
``````

So, to answer your question, yes, you are losing something desirable that the type system does for you.

Specifically, the type system makes it more difficult to thoughtlessly convert between different numeric types which can result in the attributes of one numeric type (e.g., `Int`) unexpectedly leaking into apparent uses of other numeric types (e.g., `Integer`). If you throw `fromIntegral` and other polymorphic conversions into mathematical functions without carefully considering the implementation, you are likely to introduce similar sorts of errors.

So, how should you write mathematical functions in Haskell?

Well, as a general approach, polymorphic Haskell mathematical functions are typed and written to work within a specific numeric type to the extent possible. So, the signature of `(+)` is:

``````(+) :: (Num a) => a -> a -> a
``````

meaning that the arguments each have the same type, and that will also be the type of the result. If I'm using an `Int`, I know that overflow may be an issue. If I'm using an `Integer`, I know that it won't. If I'm using a `Double`, I know that adding one to a huge number might still be equal to the huge number, but at least it won't be negative (as it might with `Int`).

If I combine a whole bunch of computations:

``````myRoot :: Float -> Float -> Float
myRoot a b c = (-b + sqrt (b*b - 4*a*c)) / (2*a)
``````

I know that the entire computation is taking place with operations on `Float`s and not secretly involving `Float`-to-`Double`-to-`Float` conversions.

You should try to write your own mathematical functions this way, and leave conversions to the user of your function, where they will be clear and explicit, and the user will have (hopefully) demonstrated that they know what they're doing.

Now, `fact` is actually a bit of a special case. If you were going to follow the advice above (i.e., write functions that work within a single numeric type), then you might favor a signature more like:

``````fact3 :: (Num a, Enum a) => a -> a
fact3 n = product [1..n]
``````

This is what @gigabytes suggested. This is probably okay, but it can lead to some odd results:

``````> fact3 2.5
6.0
>
``````

The problem is that `fact` only makes sense as a factorial function when applied to integers, and thoughtless application to a non-integer probably represents a programming error. Better to let the type system help out by using one of the alternative type signatures above:

``````> fact2 2.5
...type error...
>
``````

If the programmer really wanted to take a factorial of a non-integer, he or she should make the desired behavior explicit:

``````> fact2 (floor 2.5)
2
> fact2 (ceiling 2.5)
6
>
``````

Similar reasoning leads to types like:

``````round :: (RealFrac a, Integral b) => a -> b
``````

and the multiple power operators:

``````(**) :: Floating a => a -> a -> a
(^) :: (Integral b, Num a) => a -> b -> a
(^^) :: (Fractional a, Integral b) => a -> b -> a
``````

which -- except for `(**)` -- don't follow the "work in one type" pattern.

All of this speaks to your last question. The reason that operations like:

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

have restrictive types isn't that the type system can't express "use whichever type is bigger", it's that Haskell programmers don't WANT the type system to express that concept, at least in the context of different numeric types. They value the fact that `(/)` and `div` are different operators, and that the type of `(/)` makes it clear that the operation will be taking place within a particular numeric type without implicit coercions behind the programmer's back.

The drawback is that hundreds of new Haskell programmers have been stymied by:

``````mean xs = sum xs / length xs
``````

but it's generally been considered a small price to pay.