help from the community?

Iavor Diatchki iavor.diatchki at gmail.com
Fri Jan 26 19:26:05 EST 2007


Hello,

On 1/26/07, Malcolm Wallace <Malcolm.Wallace at cs.york.ac.uk> wrote:
> > [ scheme  = 'forall' tvars '.' opt_ctxt type ]
> > The non-terminal 'tvars' is a sequence of type variables that are
> > separated by blank spaces. We have a choice if we should allow empty
> > quantifier sequences.
> > PROPOSAL: be liberal:
> >   * allow empty quantifier lists
> >   * allow variables that are not mentioned in the body of a type (but warn)
> >   * allow predicates that do not mention quantified variables (but warn?)
>
> I cannot see how an empty list of tyvars is useful or desirable in
> practice:
>     data Foo = Foo (forall . Int)
> is equivalent to just
>     data Foo = Foo Int
> so why bother to permit the former?  It probably indicates some error in
> the thinking of the programmer, so the compiler should bring it to her
> attention.
>
> On the other hand, I can imagine a use for phantom type variables in the
> quantifier (especially if they occur in multi-parameter predicates, but
> not in the type).  So I think accepting them with a warning is
> reasonable.
>
> I can also imagine predicates that do not mention locally-quantified
> variables - the assumption must be that they mention variables bound on
> the LHS of the datatype decl instead?  e.g. the Show predicate here:
>
>     data Foo a b = Foo a b
>                  | Bar (forall c . (Show b, Relation b c) => (b,c))
>
> Hmm, maybe a simpler version of this example would illustrate what you
> mean by the proposal (first of the three bullets) to allow an empty
> quantifier list:
>
>     data Foo a b = Foo a b
>                  | Bar (forall . Show b => b)
>
> In which case, does this even count as a polymorphic component at all?
> Is it not rather GADT-like instead?
>
>     data Foo a b where
>       Foo :: a -> b -> Foo a b
>       Bar :: Show b => b -> Foo a b

I was thinking that we should allow those special cases because I
could not see a reason to disallow them (rather then having a
compelling example to use them).   You make a good point though, that
some of them might indicate an error in the program.  So, I guess, the
main decision is: do we want to make them illegal (i.e., require an
error) or suggest that implementations report a warning?  I have no
strong feelings either way, but I guess we need to pick something.

> > Constructor that have polymorphic components cannot appear in the
> > program without values for their polymorphic fields.
>
> I didn't fully understand this requirement.  If Haskell-prime gets
> rank-2 or rank-n types, then do we need to restrict constructors in this
> way?

The issue is the same as for rank-2 types.  My suggestion is based on
the design adopted by Hugs.  The basic idea is that by requiring that
functions with rank-2 types (in particular, constructors that have
polymorphic fields) are applied to all their polymorphic arguments, we
ensure that expressions can be typed by simple types as in HM (and not
type schemes).

On the pragmatic side this has the benefit that the rank-2 type
extension is quite easy to add to a Haskell'98 implementation:  the
arguments to rank-2 functions are checked pretty much in the same way
as expressions with explicit type signatures.  The only difference is
that the type signature may contain free type variables which doesn't
happen in Haskell 98.

On the theoretical side we have the benefit that this fairly
conservative extension to the type system (we are still working
essentially in HM) gives us a big increase in expressiveness (e.g., we
can encode System F programs in Haskell).  The reason that the type
system extension is quite simple is that Haskell 98 compares types for
equality by name (as opposed to examining their structure).

Other alternatives are systems like MLF (by Didier Le Botlan and
Didier Rémy) and the relaxed system implemented by GHC.  I think that
they are both quite interesting but I must admit that for the purposes
of Haskell' I am partial to the simplicity of Hug's design.  The
reason is that I feel that I can explain it to an ordinary Haskell
programmer without too much difficulty and it has been sufficient for
the situations when I've used rank-2 types.  I could be unfairly
biased, however, which is why discussions are most welcome! :-)

-Iavor


More information about the Haskell-prime mailing list