FlexibleContexts and FlexibleInstances

Niklas Broberg niklas.broberg at gmail.com
Wed Jun 10 20:29:18 EDT 2009


Hi Claus,

What you describe is exactly how I would *want* things to work. It's
nice to hear my wishes echoed from a user perspective. :-)

On Wed, Jun 10, 2009 at 4:43 PM, Claus Reinke<claus.reinke at talk21.com> wrote:
> just a few comments from a user (who would really, really, like to be
> able to define pragma collections, so that he doesn't have to switch
> on half a dozen separate extensions every time;-).
>
>> The following toy program requires MultiParamTypeClasses OR
>> FlexibleContexts in order to be accepted by GHC(i):
>>
>>> f :: (T a b) => a -> Int
>>> f _ = 0
>>
>> This of course assumes that we import the definition of T, we *must*
>> have MultiParamTypeClasses enabled if we want to declare T. Both
>> extensions thus enable classes with more than one argument to appear
>> in contexts.
>
> Only MultiParamTypeClasses does (and neither extension is needed in the
> module defining 'f', if 'T' is imported, which suggests that
> MultiParamTypeClasses is propagated to importers - this isn't true for
> most other extensions). The documentation still points to -fglasgow-exts, so
> it doesn't seem to answer these questions..

Right you are - which seems very strange to me. GHC accepts the module
defining 'f' with no flags at all, even though it is clearly not
Haskell 98. I'd go so far as to say that's a bug (as opposed to just
unwanted/unexpected behavior).

>>> f :: (T a ()) => a -> Int
>>> f _ = 0
>>
>> i.e. changing the second argument to T to () instead, means we now
>> *must* have FlexibleInstances, in order to allow the non-tyvar
>> argument. This is nothing surprising, this is what FlexibleInstances
>> are supposed to do.
>
> You mean FlexibleContexts.

Indeed I do.

>> Now, FlexibleInstances *also* lifts the restriction on contexts, just
>> like FlexibleContexts - but *only* for the contexts of instance
>> declarations.
>
> No. FlexibleInstances is about instance *heads*, FlexibleContexts is about
> contexts everywhere (in practice, there are some bugs;-).

Right, this is exactly what I *want* should happen, both as a user and
as an implementor, but that's not how GHC does it. FlexibleInstances
do enable FlexibleContexts for contexts in instance declarations -
which I think is a wart.

>   class T a b -- requires MultiParamTypeClasses   instance T a a -- requires
> FlexibleInstances   instance Eq () => T a [b] -- requires FlexibleContexts
> instance Eq [a] => T a b -- requires UndecidableInstances

Agreed - but here you avoid the tricky cases like my 'f' above. ;-)

What I would want, and what I believe you want as well, is the following:

========================================
** MultiParamTypeClasses:

Enables more than one parameter in class declarations, instance heads
and more than one argument to class assertions in contexts everywhere.
Formally, it would mean the following changes to the Haskell 98
syntax:

topdecl         ->      class [scontext =>] tycls tyvar1 ... tyvarn
[where cdecls]       (n >=1)
                 |       instance [scontext =>] qtycls inst1 ... instn
[where idecls]       (n >=1)

context         ->      class
       |       ( class1 , ... , classn )       (n>=0)
class   ->      qtycls cls1 ... clsn        (n>=1)
cls   ->      tyvar
       |       ( tyvar atype1 ... atypen )      (n>=1)

scontext        ->      simpleclass
       |       ( simpleclass1 , ... , simpleclassn )   (n>=0)
simpleclass     ->      qtycls scls1 ... sclsn        (n>=1)
scls   ->      tyvar


** FlexibleContexts:

Enables the use of non-tyvar (or tyvar applied to types) arguments to
class assertions in contexts everywhere (orthogonal to whether there
can be several arguments or just one). Formally it means the following
syntactic changes to Haskell 98:

fcontext        ->      fclass
       |       ( fclass1 , ... , fclassn )     (n>=0)
fclass  ->      qtycls atype1 ... atypen          (n>=1)

topdecl         ->      data [fcontext =>] simpletype = constrs [deriving]
                |       newtype [fcontext =>] simpletype = newconstr [deriving]
                |       class [fcontext =>] tycls tyvar [where cdecls]
                |       instance [fcontext =>] qtycls inst [where idecls]

gendecl         ->      vars :: [fcontext =>] type

for the single-argument case. (Note that I wrote type in my proposal
in the OP, but it should of course be atype.)


** FlexibleInstances:

Enables the use of arguments other than type constructors (possibly
applied to tyvars) in instances *heads* (orthogonal to whether there
can be one or more arguments, and what the context may look like).
Formally it means the following syntactic changes to Haskell 98:

topdecl         ->      instance [scontext =>] qtycls inst [where idecls]
inst   ->      atype

for the single-parameter standard-context case. (Note again that it
should be atype and not type as I wrote in the OP.)
========================================

This of course only touches the syntactic part. It doesn't attempt to
track things like 'instance (T a a) => R a b' that would be enabled by
FlexibleContexts, nor does it attempt to track things like the
Paterson conditions, but the syntax is all I'm interested in at the
moment. This is the stance I will use for haskell-src-exts, unless
someone protests wildly.

If there is any interest, I can also propose these cases as bug reports to GHC.

I hesitate to make formal proposals (e.g. for Haskell') regarding
these extensions since I'm not sure I have the full story regarding
the non-syntactic parts. But if there is a particular interest in that
then I might go the extra mile there too.

Cheers,

/Niklas


More information about the Glasgow-haskell-users mailing list