Haskell : understanding "No instance for" error messages in ghci

ghc, ghci, haskell, winghci

Solution

My intention is to complement ehird's answer with a little bit more explanation. When you wrote the expression

3 4

Then the Haskell interpreter thinks that you are trying to apply the function `3` to whatever `4` is. In order for Haskell to interpret `3` as a function, it needs to make a call to the function

fromInteger :: Integer -> (a -> b)

in order to get a function (i.e. something of type `a -> b`) from the integer `3`. Now, `fromInteger` is defined in the `Num` typeclass to have the signature

instance Num x where
    fromInteger :: Integer -> x

i.e. when you make the type `x` an instance of the `Num` class, you give an implementation of `fromInteger` which tells Haskell how to convert an integer literal into an `x`. In your case, `x` is the function type `a -> b`. So let's do it!

First, some boilerplate. To make `x` an instance of `Num` Haskell requires that we also make it an instance of `Show` and `Eq`:

instance Show (a -> b) where show f = "<function>"
instance Eq (a -> b) where f == g = False

Now let's say we want to interpret `3 4` as "4 modulo 3". Then we need to tell Haskell how to interpret any integer as a function that calls `mod`. Moreover, since `mod` only accepts integral types (it has the signature `mod :: Integral a => a -> a -> a`) then we need to restrict the types of `a` and `b` to be integral as well:

instance (Integral a, Integral b) => Num (a -> b) where

To make an instance of `Num` we need to give implementations of `(+)`, `(-)`, `(*)` and `fromIntegral` (actually we should define a couple of other functions too, but let's not worry about that now).

There's a fairly natural way to define addition, subtraction and multiplication (all code from here forms part of the `Num` instance and should be indented relative to the instance declaration)

    f + g = \x -> f x + g x
    f - g = \x -> f x - g x
    f * g = \x -> f x * g x

i.e. when you add two functions `f` and `g`, you get a new function that applies both `f` and `g` to its argument, and then adds them together. Since we required that the result of applying `f` and `g` was of integral type, we know that it makes sense to add up their outputs.

To interpret an integer as a function we can write

    fromInteger n = \m -> fromIntegral m `mod` fromIntegral n

i.e. when we have an integer `n`, we return a function of a parameter `m` that, when called, ensures that both arguments are of the same type (by calling `fromIntegral` on both of them) and then uses them as arguments to the function `mod`.

Finally, a bit more boilerplate to stop Haskell complaining:

    abs f = undefined
    signum f = undefined

We can test this out. I have my code in a file called numfun.hs. I boot up the Haskell interpreter and load my file:

Prelude> :l numfun.hs
[1 of 1] Compiling Main             ( numfun.hs, interpreted )
Ok, modules loaded: Main.

Now I can define some functions:

*Main> let f = (+ 1)
*Main> let g = (* 2)

I can add them or subtract them:

*Main> (f + g) 3   -- (3+1) + (3*2)
10
*Main> (f - g) 3   -- (3+1) - (3*2)
-2

And I can call numbers as functions:

*Main> 3 4         -- 4 `mod` 3
1

Problem

Question 1 Hi, if in WinGHCi I intentionally do the following wrong piece of code : ``` 3 4 ``` Then the error message I get is ``` <interactive>:1:1: No instance for (Num (a0 -> t0)) arising from the literal `3' Possible fix: add an instance declaration for (Num (a0 -> t0)) In the expression: 3 In the expression: 3 4 In an equation for `it': it = 3 4 ``` What exactly does `No instance for (Num (a0 -> t0))` mean? Question 2 Why does the following piece of code : ``` (+) 2 3 4 <interactive>:1:7: No instance for (Num (a0 -> t0)) arising from the literal `3' Possible fix: add an instance declaration for (Num (a0 -> t0)) In the second argument of `(+)', namely `3' In the expression: (+) 2 3 4 In an equation for `it': it = (+) 2 3 4 ``` yield a slightly different error from the second piece of code : ``` 2+3 4 <interactive>:1:3: No instance for (Num (a1 -> a0)) arising from the literal `3' Possible fix: add an instance declaration for (Num (a1 -> a0)) In the expression: 3 In the second argument of `(+)', namely `3 4' In the expression: 2 + 3 4 ``` Namely in the first piece of code we have `No instance for (Num (a0 -> t0))` where as in the second piece of code we have `No instance for (Num (a1 -> a0))`. [Response to ehird] (Questions moved from answer comments) : 1) I appreciate the latter two expressions are different, but are you saying that I should not try to understand why the interpreter chooses `(Num (a0 -> t0))` for the former and `(Num(a1 -> a0))` for the latter, besides the fact that they are different? 2)Hi, and with the former when you say "But there's no Num instance for functions" what do you mean? Sorry I am not clear on what the concept of an instance is. Furthermore, just out of curiosity, could you use your instance `Num (a -> b)` method to somehow tell the interpreter to interpret `3 4` as `4 modulo 3`?

Original source