GHC extension semantics that allow method restrictions (-XConstrainedClassMethods)

The following is the GHC user guide (Haskell Platform 2012.4.0.0) ...

7.6.1.3. Class Method Types

Haskell 98 forbids class types of classes to mention class type variable restrictions, as follows:

class Seq sa where fromList :: [a] -> sa elem :: Eq a => a -> sa -> Bool 

The elem type is illegal in Haskell 98 because it contains a restriction of Eq a that restricts only a class type variable (in this case a). GHC cancels this restriction (flag -XConstrainedClassMethods).

However, I do not see any explanation of what this means. I see two possibilities ...

  • The Seq class implicitly gets the constraint Eq a from elem .
  • The elem method cannot be used for a class of type Seq in cases where a not a member of the class Eq (or where it is a member but unknown where elem used).

I strongly suspect (2) because it seems to be potentially useful, while (1) seems to be useless. (2) it basically allows you to define methods for cases where they can be supported without restricting the type class to just being established for these cases.

An example seems to motivate just that: the idea is that elem often a useful operation for sequences, too valuable for life without it, but we also want to support sequences where elem not supported, for example, sequences of functions.

Am I right, or am I missing something? What is the semantics for this extension?

+4
source share
1 answer

NOTE: there seems to be an error in GHC> = 7 , which makes the GHC class methods acceptable even in Haskell 98 mode.

In addition, the example from the manual is always taken when you enable MultiParamTypeClasses , regardless of whether the ConstrainedMethodTypes extension is enabled (also a likely error).


In type elem :

 elem :: Eq a => a -> sa -> Bool 

a and s are class type variables, and Eq a is a restriction on a class type variable a . As the manual says, Haskell 98 prohibits such restrictions (FWIW, it also prohibits classes with multiple parameters). Therefore, the following code should not be accepted in Haskell 98 mode (and I think that it is also forbidden in Haskell 2010):

 class Compare a where comp :: Eq a => a -> a -> Bool 

And indeed, GHC 6.12.1 rejects it:

 Prelude> :load Test.hs [1 of 1] Compiling Main ( Test.hs, interpreted ) Test.hs:3:0: All of the type variables in the constraint `Eq a' are already in scope (at least one must be universally quantified here) (Use -XFlexibleContexts to lift this restriction) When checking the class method: comp :: (Eq a) => a -> a -> Bool In the class declaration for `Compare' Failed, modules loaded: none. Prelude> :set -XConstrainedClassMethods Prelude> :load Test.hs [1 of 1] Compiling Main ( Test.hs, interpreted ) Ok, modules loaded: Main. 

The idea is that you should use superclass restrictions instead:

 class (Eq a) => Compare a where comp :: a -> a -> Bool 

Regarding semantics, you can easily check if a class method constraint is not limited to adding a superclass constraint with the following code:

 {-# LANGUAGE ConstrainedClassMethods #-} module Main where class Compare a where comp :: (Eq a) => a -> a -> Bool someMethod :: a -> a -> a data A = A deriving Show data B = B deriving (Show,Eq) instance Compare A where comp = undefined someMethod AA = A instance Compare B where comp = (==) someMethod BB = B 

Testing with GHC 6.12.1:

 *Main> :load Test.hs [1 of 1] Compiling Main ( Test.hs, interpreted ) Ok, modules loaded: Main. *Main> comp A <interactive>:1:0: No instance for (Eq A) arising from a use of `comp' at <interactive>:1:0-5 Possible fix: add an instance declaration for (Eq A) In the expression: comp A In the definition of `it': it = comp A *Main> someMethod AA A *Main> comp BB True 

Answer: no, it is not. The restriction applies only to a method with a limited type. So you are right, this is opportunity number 2.

+5
source