Thomas Crowley
Thomas Crowley

Reputation: 1108

No instance for (Num Nat) arising from the literal ‘1’

I am trying to create some functions using natural numbers.

import Prelude
data Nat = Zero | Succ Nat

add:: Nat -> Nat -> Nat
add Zero n = n
add (Succ m) n = Succ (add m n)

mult :: Nat -> Nat -> Nat
mult x Zero = Zero
mult x (Succ y) = add x (mult x y)

then when I run

mult 3 5

I get this error:

<interactive>:38:6: error:
• No instance for (Num Nat) arising from the literal ‘3’
• In the first argument of ‘mult’, namely ‘3’
  In the expression: mult 3 5
  In an equation for ‘it’: it = mult 3 5

I am relatively new to Haskell so any help would be appreciated. Thanks in advance

Upvotes: 0

Views: 1405

Answers (2)

SwiftsNamesake
SwiftsNamesake

Reputation: 1578

TL;DR

GHC is telling you exactly what you need to know: that your Nat type is not in fact an instance of Num. This is the typeclass that allows integer literals to be polymorphic (via fromInteger).


Integer literals in Haskell are polymorphic, so mult 3 5 could work. The problem is that you haven't explained how to turn 3 and 5 into Nats.

The most straight-forward way of solving the problem is to implement Num for your type. You could also create a separate natFromInteger if you don't wish to implement the entire set (such as subtraction, which is a partial function for natural numbers).

Num solution:

instance Num Nat where
  fromInteger 0 = Zero
  fromInteger n = Succ . fromInteger $ n - 1

You could simplify the solution via fromEnum as @leftroundabout suggests.

A free standing natFromInteger solution looks about the same:

natFromInteger :: Integer -> Nat
natFromInteger 0 = Zero
natFromInteger n = Succ . natFromInteger $ n - 1

This solution will not let you convert literals implicitly. On the other hand, it avoids the issue of having partial or unimplemented functions, as I mentioned before.

A compromise: RebindableSyntax

There is a third option, which let's you override fromInteger without implementing the remaining litany of mathematical functions and operators from Num: using the GHC extension RebindableSyntax. Have a look at this answer for details.

Upvotes: 3

leftaroundabout
leftaroundabout

Reputation: 120711

How is the compiler supposed to know that Zero is intended to represent the number 0, as well as Succ . Succ $ Zero the number 2 and so on? It would have to more or less blindly guess that this is what you intend.

You can explicitly tell it to handle number literals this way, though:

instance Num Nat where
  fromInteger 0 = Zero
  fromInteger n = Succ . fromInteger $ n - 1

Furthermore, even if the compiler thus knows how Nats can be defined through number literals, it won't be able to display a given/computed Nat value. For that, there is a natural automatic fix, though:

data Nat = Zero | Succ Nat
   deriving (Show)

You can also add Eq, Ord and Enum to the deriving list; in fact the derived Enum instance does pretty much that “blind guessing” as to what Nat value represents what number. Actually I've just noticed that Enum can't be derived on recursive types like Nat; if that were possible you could write:

instance Num Nat where
  fromInteger = toEnum . fromInteger

Upvotes: 6

Related Questions