Marcus Ruddick
Marcus Ruddick

Reputation: 10375

Trouble getting types to match up in Haskell

I am trying to get a list of the digits from a number, here is my code:

digits x = if x > 0 then (i : digits (floor (x / 10))) else [i]
    where i = (mod x 10)

The error I get for this code is:

No instance for (Integral a0) arising from a use of ‘it’
    The type variable ‘a0’ is ambiguous
    Note: there are several potential instances:
      instance Integral Integer -- Defined in ‘GHC.Real’
      instance Integral Int -- Defined in ‘GHC.Real’
      instance Integral Word -- Defined in ‘GHC.Real’
    In the first argument of ‘print’, namely ‘it’
    In a stmt of an interactive GHCi command: print it

what am I doing wrong?

Upvotes: 1

Views: 58

Answers (1)

Alec
Alec

Reputation: 32309

To elaborate on Carsten's comment, the problem is that Haskell infers the type signature

digits :: (RealFrac a, Integral a) => a -> [a]

when what you wanted was

digits :: Integral a => a -> [a]

The reason it infers the former is that you use (/) and floor, which are defined in the Fractional and RealFrac classes. As leftaroundabout points out, this isn't really a problem until you try to run your function with an actual number, at which point Haskell fails to find a good number type to default to (Haskell number literals are actually polymorphic, and there are special defaulting rules for when you don't explicitly declare a type), hence the weird error message. You would get a more descriptive error message if you tried something like digits (1 :: Int):

<interactive>:19:1: error:
  • No instance for (RealFrac Int) arising from a use of ‘digits’
  • In the expression: digits (1 :: Int)
    In an equation for ‘it’: it = digits (1 :: Int)

The fix, as Carsten pointed out, is to use div instead of (/) and floor.

Upvotes: 2

Related Questions