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`?