3

I was attempting to understand the example given at this question about variadic functions and tried to modify the code from:

class SumRes r where 
    sumOf :: Integer -> r

instance SumRes Integer where
    sumOf = id

instance (Integral a, SumRes r) => SumRes (a -> r) where
    sumOf x = sumOf . (x +) . toInteger

to this:

class SumRes r where 
    sumOf :: Int -> r

instance SumRes Int where
    sumOf = id

instance (SumRes r) => SumRes (Int -> r) where
    sumOf x = sumOf . (x +) 

I get a Illegal instance declaration for SumRes (Int -> r). Can someone explain what this means and what is the constraint I'm against?

Community
  • 1
  • 1
me2
  • 3,933
  • 4
  • 17
  • 16

2 Answers2

5

You're just running into the limits of the Haskell standard. Standard Haskell only permits a restricted set of instance declarations. In particular all instances have to be "simple" in the sense that they're a type applied to zero or more type variables.

This means you can have instances for Int, Maybe or Maybe a. However, you cannot have an instance for something like Maybe Int. That's the problem you're running into here: your instance has a type (->) applied to Int as well as a variable.

However, despite the fact that this behavior isn't in the standard, it still makes sense, so you can enable it with an extension. That's what FlexibleInstances does, with the obvious caveat that your code is not standard Haskell any more.

Tikhon Jelvis
  • 67,485
  • 18
  • 177
  • 214
3

In standard Haskell, instance heads (the part after the class name in an instance) are required to be of the form T a1 a2 .. an where T is a type constructor and the ai are distinct type variables.

The compiler complains because your instance head is (->) Int r, and Int is not a type variable.

In GHC, this restriction can be lifted using the FlexibleInstances extension, and the only real downside to doing so is a possible lack of portability.

hammar
  • 138,522
  • 17
  • 304
  • 385