Oleiade
Oleiade

Reputation: 6274

Custom typeclass instantiation: couldn't match expected type ‘b’ with actual type ‘Int’

I am currently trying to implement a typeclass that allows me to convert any of custom types to an Integral (those types should all be convertible to an index or a weight). In this specific case I want to use it to make sure that a musical note, on a given octave, can be converted to the index of a piano keyboard key:

import Data.Int

class Convertible a where
  toIntegral :: Integral b => a -> b

data Note = Note Tone Int

instance Convertible Note where
    toIntegral (Note t o) = o * 12 + toIntegral t

However the compiler complains my implementation of toIntegral for Note does not comply with my Convertible typeclass.

    • Couldn't match expected type ‘b’ with actual type ‘Int’
  ‘b’ is a rigid type variable bound by
    the type signature for:
      num :: forall b. Integral b => Note -> b
    at src/Note.hs:11:5
• In the expression: octave * 12 + (num tone)
  In an equation for ‘num’:
      num (Note tone octave) = octave * 12 + (num tone)
  In the instance declaration for ‘Convertible Note’
• Relevant bindings include
    num :: Note -> b (bound at src/Note.hs:11:5)

As far as I understand, it considers the content of my toIntegral function evaluates to an a -> Int, when I constrained it to be an Integral => b -> a -> b. Now I don't understand what's wrong, because Int implements the Integral typeclass, right?

Can you help me understand what I'm obviously doing wrong here?

Upvotes: 2

Views: 133

Answers (1)

chi
chi

Reputation: 116139

Type variables are chosen by the caller, not by the callee. In your case, toIntegral can not choose b, its caller does. According to its type, all of these uses must type check

toIntegral (Note t o) :: Int
toIntegral (Note t o) :: Integer
toIntegral (Note t o) :: Word32
-- etc.

The solution is to convert Ints as well, i.e. convert o, so to return any integral b, and not just an Int.

For instance, fromIntegral o can convert o to any Num type, hence any Integral one.

Anyway, are you sure you really need that type for your toIntegral?

Upvotes: 3

Related Questions