Re: [Haskell-cafe] closed classes [was: Re: exceptions vs. Either]

2004-08-14 Thread Frank Atanassow
On Aug 9, 2004, at 5:00 PM, Simon Peyton-Jones wrote:
Closed classes are certainly interesting, but a better way to go in 
this case is to allow the programmer to declear new kinds, as well as 
new types.  This is what Tim Sheard's language Omega lets you do, and 
I'm considering adding it to GHC.
FWIW, Martin Wehr designed a Haskell-like type system with:
* not only datakinds, but datasuperkinds, datasupersuperkinds, etc., in 
short, data-n-types for every finite dimension n, all parametric,

* along with parametrically polykinded, polysuperkinded, etc., in 
short, poly-n-morphic functions,

* along with map, simple folds and nested folds for all these things,
* not to mention an algorithm for principal type inference
in his 1998 paper:
@misc{ wehr98higher,
  author =   "M. Wehr",
  title ="Higher order algebraic data types",
  text = "Martin Wehr. Higher order algebraic data types
  (full paper). Technical report, University of
  Edinburgh, URL
  http://www.dcs.ed.ac.uk/home/wehr, July 1998.",
  year = "1998",
  url =  "citeseer.nj.nec.com/wehr98higher.html"
}
The title of the paper is a bit misleading: "higher-dimensional" is 
better than "higher-order", as higher-order functions are the chief 
thing missing from Wehr's system. But these are easily added in the 
standard fashion, which is to say, only at the value level, and by 
simply neglecting the problem of defining folds for datatypes involving 
(->).

Two significant differences between Wehr's system and the one Simon 
described is that every kind in Wehr's system has values, and there is 
no distinguished kind *.

I tried to champion this (very incoherently) in a talk at the Hugs/GHC 
meeting in, I think, 2000, where Tim also presented some of his early 
ideas on datakinds.

(BTW, given such an expressive system, I think you may find, as I did, 
that the number of ways to represent what amount to essentially the 
same type grows ridiculously large, and this is one of the motivations 
for treating more general notions of type equivalence than equality, 
like for example canonical isomorphy as I am doing in a forthcoming 
paper.)

There is also an extended abstract of Wehr's paper in CTCS (no citation 
handy---I'm posting this from at home), and a categorical semantics 
which is, however, not for the faint of heart:

@article{ wehr99higherdimensional,
  author =   "Martin Wehr",
  title ="Higher-dimensional syntax",
  journal =  "Electronic Notes in Theoretical Computer Science",
  volume =   29,
  year = 1999,
  url =  "citeseer.nj.nec.com/wehr99higher.html"
}
Eelco Visser also defines a notion of multi-level type system, and 
gives several examples of how they can be used, in his PhD thesis. One 
of the examples, as I recall, shows how datakinds and polykinded 
functions subsume uni-parameter type classes (without overlapping 
instances).

Regards,
Frank
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


RE: [Haskell-cafe] closed classes [was: Re: exceptions vs. Either]

2004-08-12 Thread MR K P SCHUPKE
>but if f is exported, that's probably not what you want.

Why...

Read my post carefully - I am suggesting that you close the class
on IMPORT so

module X

import a
import b 
import c

So we close the class here - after reading all possible instances
from imported files a,b, and c

Keean.
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


RE: [Haskell-cafe] closed classes [was: Re: exceptions vs. Either]

2004-08-12 Thread Simon Peyton-Jones
but if f is exported, that's probably not what you want.  And if you give a type sig 
to f, 
f:: forall a. C a => a -> Maybe a
the type sig will say it's polymorphic, while the improvement rule will say that a 
must be Int.

Simon

| -Original Message-
| From: André Pang [mailto:[EMAIL PROTECTED]
| Sent: 12 August 2004 14:52
| To: Simon Peyton-Jones
| Cc: MR K P SCHUPKE; [EMAIL PROTECTED]; [EMAIL PROTECTED]
| Subject: Re: [Haskell-cafe] closed classes [was: Re: exceptions vs. Either]
| 
| On 12/08/2004, at 11:05 PM, Simon Peyton-Jones wrote:
| 
| > module M where
| >
| > class C a where
| >op :: a -> a
| >
| > instance C Int where
| >op x = x+1
| >
| > f x = Just (op x)
| >
| > Under your proposal, I'd infer f :: Int -> Maybe Int, on the grounds
| > that C is closed and there is only one instance.
| 
| If I'm reading Keean's posts right, that's exactly his point: if you
| only have one instance of class C, then it's valid to improve f's type
| to :: Int -> Maybe Int, right?
| 
| If, on the other hand, you had another instance (e.g. instance C Bool),
| then the signature of f would have to remain polymorphic.
| 
| 
| --
| % Andre Pang : trust.in.love.to.save

___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] closed classes [was: Re: exceptions vs. Either]

2004-08-12 Thread André Pang
On 12/08/2004, at 11:05 PM, Simon Peyton-Jones wrote:
module M where
class C a where
   op :: a -> a
instance C Int where
   op x = x+1
f x = Just (op x)
Under your proposal, I'd infer f :: Int -> Maybe Int, on the grounds
that C is closed and there is only one instance.
If I'm reading Keean's posts right, that's exactly his point: if you 
only have one instance of class C, then it's valid to improve f's type 
to :: Int -> Maybe Int, right?

If, on the other hand, you had another instance (e.g. instance C Bool), 
then the signature of f would have to remain polymorphic.

--
% Andre Pang : trust.in.love.to.save
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


RE: [Haskell-cafe] closed classes [was: Re: exceptions vs. Either]

2004-08-12 Thread Simon Peyton-Jones
module M where

class C a where
   op :: a -> a

instance C Int where
   op x = x+1

f x = Just (op x)

Under your proposal, I'd infer f :: Int -> Maybe Int, on the grounds
that C is closed and there is only one instance.

Simon

| -Original Message-
| From: [EMAIL PROTECTED]
[mailto:[EMAIL PROTECTED] On Behalf Of MR
| K P SCHUPKE
| Sent: 12 August 2004 14:03
| To: [EMAIL PROTECTED]; [EMAIL PROTECTED]
| Subject: Re: [Haskell-cafe] closed classes [was: Re: exceptions vs.
Either]
| 
| Okay anybody whish to argue against these points:
| 
|   1) closed or open is the same if no instances overlap
| 
|   2) overlapping instances (open or closed) can break
|  code in modules which import the defining module
|  if a new instance is declared in any imported
|  module.
| 
|   3) code changes in non-imported modules cannot have
|  any affect on _this_ module. (And here I count
|  any module in the import tree as imported - at
|  least in terms of recompilation dependancies)
| 
| The conclusion appears to be it is overlapping instances
| that cause code to be 'breakable' by simply defining a new
| instance and not closing the class. Closing the class
| would appear to have no adverse affects on existing
| programs (as it allows better improvement rules) all existing
| programs that compile without the better improvement rules
| should still compile - just a few more programs will be
| valid with the closed assumption?
| 
|   Keean.
| ___
| Haskell-Cafe mailing list
| [EMAIL PROTECTED]
| http://www.haskell.org/mailman/listinfo/haskell-cafe
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] closed classes [was: Re: exceptions vs. Either]

2004-08-12 Thread MR K P SCHUPKE
Okay anybody whish to argue against these points:

1) closed or open is the same if no instances overlap

2) overlapping instances (open or closed) can break
   code in modules which import the defining module
   if a new instance is declared in any imported
   module.

3) code changes in non-imported modules cannot have
   any affect on _this_ module. (And here I count
   any module in the import tree as imported - at
   least in terms of recompilation dependancies)

The conclusion appears to be it is overlapping instances
that cause code to be 'breakable' by simply defining a new
instance and not closing the class. Closing the class
would appear to have no adverse affects on existing 
programs (as it allows better improvement rules) all existing
programs that compile without the better improvement rules
should still compile - just a few more programs will be
valid with the closed assumption?

Keean.
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] closed classes [was: Re: exceptions vs. Either]

2004-08-12 Thread Marcin 'Qrczak' Kowalczyk
W liście z czw, 12-08-2004, godz. 10:30 +0100, Keith Wansbrough napisał:

> If the compiler treated instances as closed in this way, then adding a
> new instance to the program could break existing parts of the program.
> This would be a development nightmare.

Well, this is already possible due to conflicting instances.

It implies a guideline that a library should only add instances for
classes it defines itself, or for types it defines itself. With
multiparameter classes it suffices that at least one of the types
from the instance head is new.

All other cases should be carefully examined to see if the instance is
appropriate, in particular if it's indeed the only "right" instance for
this class/types combination. If that's right, the instances should be
clearly announced in the documentation, and preferably defined in a
separate module to be imported optionally.

This increases the chance that anybody wishing to make a similar
instance will know about that module, and if he still wants to make
a separate instance, then both libraries can be linked together.

This is only a guideline, not a hard requirement.

-- 
   __("< Marcin Kowalczyk
   \__/   [EMAIL PROTECTED]
^^ http://qrnik.knm.org.pl/~qrczak/

___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] closed classes [was: Re: exceptions vs. Either]

2004-08-12 Thread MR K P SCHUPKE
>If the compiler treated instances as closed in this way, then adding a
>new instance to the program could break existing parts of the program.

But there are many ways to do this... and besides this doesn't really make sense...
consider the following:

module A
defines class X

module B imports class X defines some instances

module C imports A & B

Now, you can add any instance you like to module C and it
is never seen by modules A and B... In other words even
if you assume closed classes you cannot break an existing
module without editing that module or one imported by 
it (in which case you can break _anything_ by deleting
a function)

If you don't allow overlapping instances none of this makes
any difference anyway - closed or open ... (instance selection
cannot change if no instances are allowed to overlap)

Finally if you allow overlapping instances you can break
existing code (without the closed assumption) just by
putting in a more specific instance in a module included
in some module using the more general instance.


Thoughts? What is the problem with assuming all classes are
closed within the available context (imported modules)

Keean.
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] closed classes [was: Re: exceptions vs. Either]

2004-08-12 Thread Keith Wansbrough
> Just wondering, but what exacly is the problem with this open/closed stuff?
> As far as I understand it new instances can be added to classes in Haskell
> (because they are open)... But its not like instances can be added at link
> time, and all the instances that you wish to be considered _must_ be
> imported into the current module!
[..]

Sure it's the case that instances are closed in any given build of a
program.  But they're not closed over the (maintenance / extension)
lifetime of that program.

If the compiler treated instances as closed in this way, then adding a
new instance to the program could break existing parts of the program.
This would be a development nightmare.

This is just an example of a general principle in language / compiler
design - it's not sufficient that the behaviour be specified, it must
behave predictably from the programmer's point of view; in particular,
local changes shouldn't have global effect.  This also comes up in
optimisations - you could write a compiler that recognised occurrences
of bubble sort and replaced them with quicksort, for example, but it
wouldn't be a good idea, because a small change to the code might
cause it to no longer recognise it as bubblesort - with a consequent
asymptotic slowdown that bears no relation to the change just made.

--KW 8-)

___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] closed classes [was: Re: exceptions vs. Either]

2004-08-12 Thread MR K P SCHUPKE
Just wondering, but what exacly is the problem with this open/closed stuff?
As far as I understand it new instances can be added to classes in Haskell
(because they are open)... But its not like instances can be added at link
time, and all the instances that you wish to be considered _must_ be
imported into the current module! That means if we (for example) used
two pass compilation we could gather all the instances together first
and know that we have all instances for a given class before considering
any resolution of overlapping instances. Why is this not done?
(personally I don't mind if compilation takes longer if it makes coding
easier...)

Keean.
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


[Haskell-cafe] closed classes [was: Re: exceptions vs. Either]

2004-08-11 Thread Martin Sulzmann
Hi,

here's my take on closed classes versus kinds.

1) Closed classes:

Consider

class Foo x
instance Foo Int
instance Foo Bool

Assume we'd like to prevent that Foo has any other members besides Int 
and Bool. Haskell follows the open-world assumption. Hence, Foo t is assumed to
be true for any type t unless otherwise stated.
Oleg suggests to use functional dependency style
improvement. Indeed, we'd like to state that
"Foo x improves to False for any x different from Int and Bool".
The question is how to enforce this condition?
I don't think you can by just relying on functional dependencies.

1a) Closed classes in Chameleon:

E.g., in Chameleon we can enumerate all cases which should yield False

rule Foo Char ==> False
rule Foo (a,b) ==> False
rule Foo (a->b) ==> False
...

But what happens if we define a new type such as data Erk = ...?
Well, we'll need to add a new improvement rule

rule Foo Erk ==> False

1b) Closed-world assumption:

Alternatively, we might want to abandon the open-world assumption
and switch to a Prolog-like closed world approach. 
See section 4.2 in [1] and section 8.1 in [2] for a discussion.
Essentially, we impose that

Foo x improves to x=Int or x=Bool

We can close classes once and for all, however, we're in trouble in
case instance declarations are recursive (e.g., Simon's example
involves a recursive instance declaration!)

Ref:
[1] Object-Oriented Style Overloading for Haskell by Mark Shields and Simon Peyton 
Jones.
[2] A Theory of Overloading by Peter J. Stuckey and Martin Sulzmann


b) Kinds

There's certainly a connection between closed classes and kinds.
Assume we have a system that supports closed classes (either by
following (1a) or (1b)).
Then

kind K = T1 | T2
class C (a::K)

can be encoded by

closed class K x
instance K T1
instance K T2
-- T1 and T2 are the only members of K 

class K a => C a
-- C t implies K t which yields failure if t differs from T1 or T2

Martin


Oleg wrote:
 > Simon Peyton-Jones wrote:
 > 
 > > kind HNat = HZero | HSucc HNat
 > >
 > > class HNatC (a::HNat)
 > >
 > > instance HNatC HZero
 > > instance HNatC n => HNatC (HSucc n)
 > >
 > > There is no way to construct a value of type HZero, or (HSucc HZero);
 > > these are simply phantom types. ... A merit of declaring a kind
 > > is that the kind is closed -- the only types of kind HNat are HZero,
 > > HSucc HZero, and so on. So the class doesn't need to be closed; no one
 > > can add new instances to HNatC because they don't have any more types of
 > > kind HNat.
 > 
 > With the flag -fallow-overlapping-instances, could I still add an instance
 >  instance HNatC n => HNatC (HSucc (HSucc n))
 > or
 >  instance HNatC (HSucc HZero)
 > ??
 > 
 > 
 > If I may I'd like to second the proposal for closed classes. In some
 > sense, we already have them -- well, semi-closed. Functional
 > dependencies is the way to close the world somewhat. If we have a
 > class
 >  class Foo x y | x -> y
 >  instance Foo Int Bool
 > we are positive there may not be any instance 'Foo Int '
 > ever again, open world and -fallow-overlapping-instances
 > notwithstanding. In fact, it is because we are so positive about that
 > fact that we may conclude that "Foo Int x" implies x = Bool. At least
 > in the case of functional dependencies, the way to close the world gives
 > us type improvement rules. One might wonder if there are other ways
 > to (semi-)close the world with similar nice properties.
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


RE: [Haskell-cafe] closed classes [was: Re: exceptions vs. Either]

2004-08-09 Thread oleg

Simon Peyton-Jones wrote:

> kind HNat = HZero | HSucc HNat
>
> class HNatC (a::HNat)
>
> instance HNatC HZero
> instance HNatC n => HNatC (HSucc n)
>
> There is no way to construct a value of type HZero, or (HSucc HZero);
> these are simply phantom types. ... A merit of declaring a kind
> is that the kind is closed -- the only types of kind HNat are HZero,
> HSucc HZero, and so on. So the class doesn't need to be closed; no one
> can add new instances to HNatC because they don't have any more types of
> kind HNat.

With the flag -fallow-overlapping-instances, could I still add an instance
instance HNatC n => HNatC (HSucc (HSucc n))
or
instance HNatC (HSucc HZero)
??


If I may I'd like to second the proposal for closed classes. In some
sense, we already have them -- well, semi-closed. Functional
dependencies is the way to close the world somewhat. If we have a
class
class Foo x y | x -> y
instance Foo Int Bool
we are positive there may not be any instance 'Foo Int '
ever again, open world and -fallow-overlapping-instances
notwithstanding. In fact, it is because we are so positive about that
fact that we may conclude that "Foo Int x" implies x = Bool. At least
in the case of functional dependencies, the way to close the world gives
us type improvement rules. One might wonder if there are other ways
to (semi-)close the world with similar nice properties.

___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


RE: [Haskell-cafe] closed classes [was: Re: exceptions vs. Either]

2004-08-09 Thread MR K P SCHUPKE
>Is there any possibility of a theory that will avoid the need to replicate
>features at higher and higher levels?

If we consider types, types are a collection of values, for example we could
consider Int to be:

data Int = One | Two | Three | Four ...

Okay, so the values in an integer are connected by functions (operations
like plus, multiply) - but we can consider these externally defined (as they
are primitives). Also we have special symbols for the values of this type
(type constructors are 'values') like 1, 2, 3... etc.

Likewise Char is effectively an enumeration of ascii values (or Unicode
values). All these standard types behave like enumerations of values.

Lists are effectively nested binary products:

data List a = Cons a (List a)

But I digress, my point is that types are a 'set' of values, and so
we can consider the simplest example:

data Bool = True | False

So bool is a type and True and False are the values 'in' that type - _but_
we can also write:

kind Bool = True | False

Where Bool is a kind and True and False are values, Kinds are really a different
name for "type_of_types"... and this continues upwards forever (a 
type_of_type_of_types) ... we can effectively flatten this by considering
types as values and kinds as types. What is the difference between a type
and a value? 

So we can consider: "data Bool = True | False" to be a relationship between
elements at the Nth level (the RHS) and the N+1th level (the LHS). This
relationship could be applied at any level, and it should be possible to
detemine the level at which we wish to apply this relationship by the
context in which it is used.

Imagine a function 'not':

not :: Bool -> Bool
not True = False
not False = True

we could apply this at the values level:

> not True
False

The type level:

class (Bool a,Bool b) => Not a b
| a -> b
instance True False
instance False True

How does this differ from the original functional form?
can we imagine doing:

not' :: Not a b => a -> b

but perhaps writing it:

not' :: Bool a => a -> not a

After all is not 'not'  a complete function from Bool to Bool, whatever Bool is?
(Bool could be a type or a type of types, or a type of type of types...)

Would this not result in greater code re-use? Perhaps classes would become redundant
(apart from being used to allow overloading...)

My theory here is a bit shakey - but the name Martin Lof springs to mind.

Keean.

*errata - when I said "Where Bool is a kind and True and False are values" I of course
meant w
true and false are types!
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


RE: [Haskell-cafe] closed classes [was: Re: exceptions vs. Either]

2004-08-09 Thread Duncan Coutts
On Mon, 2004-08-09 at 18:05, Graham Klyne wrote:
[snip]
> and have found myself wondering if type-level lambda abstraction
> wouldn't be a useful feature to overcome this.
> 
> Your suggestion seems to be another feature in the same vein:  extending 
> data features to types.  I find myself wondering where this might all 
> end.  If types acquire many of the manipulations that are available for 
> data values, then might one find that, in turn, cases will be found that 
> seem to require similar capabilities for kinds?
> 
> Is there any possibility of a theory that will avoid the need to replicate 
> features at higher and higher levels?

As people have bee discussing recently on this list, this is what
dependent types gives you. Instead of having a hierarchy of
values->types->kinds-> ... where each is classified by the one above it
(values by types, types by kinds), dependent types allow you to have
types that depend on values in your program. It does indeed allow you to
manipulate types using the same manipulations that are available for
ordinary data values.

The trade off however is that the value system must be decidable (no
bottom allowed) or otherwise the type system is undecidable. There are
other ways of making the trade off that do allow you use general
recursion when you really need to (as Conor posted recently), but then
you loose the ability to prove certain things about your programs within
the type checking framework and you would have to go back to external
proofs. (Of course this is the situation in Haskell anyway, that these
kinds of proofs have to be done externally to the program)

Duncan

___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] closed classes [was: Re: exceptions vs. Either]

2004-08-09 Thread John Meacham
On Mon, Aug 09, 2004 at 04:00:44PM +0100, Simon Peyton-Jones wrote:
> At the moment I'm only thinking of parameter-less kind declarations but
> one could easily imagine kind parameters, and soon we'll have kind
> polymorphism  but one step at a time.
> 
> Any thoughts?  
> 

My first thought is I am going to need a better editor mode that can
tell from context whether an identifier is a value, type, or kind (or
meta-kind?) constructor and differentiate them visually :)

would these kind constructors need to be encoded into system F or the
lambda cube,  or would it be possible that they be eliminated right
after typechecking or easily desugared away like classes?

The idea is quite interesting. I was thinking about explicit kinds the
other day, but just as an idle curiosity, now that this thread has
provided some real-world interesting uses, I will have to think about
them some more :)

John


-- 
John Meacham - ârepetae.netâjohnâ 
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


RE: [Haskell-cafe] closed classes [was: Re: exceptions vs. Either]

2004-08-09 Thread Graham Klyne
At 16:00 09/08/04 +0100, Simon Peyton-Jones wrote:
Any thoughts?
Well, a thought, but I'm not sure that it leads anywhere useful.
In the process of learning Haskell, I've vaguely observed to myself that 
features introduced for describing data (i.e. type expressions) seem to 
also be usable in higher form to describe types.  Mostly, the Haskell 
language definition resists such extension, by sticking with a very simple 
notion of kind and type construction (or is that a fundamental restriction 
of Hindley-Milner?).

For example, if I choose the "wrong" parameter ordering for a type 
constructor in a class declaration, I sometimes find the resulting class 
cannot be used in the ways intended --only one possible sequence of partial 
instantiation is possible-- and have found myself wondering if type-level 
lambda abstraction wouldn't be a useful feature to overcome this.

Your suggestion seems to be another feature in the same vein:  extending 
data features to types.  I find myself wondering where this might all 
end.  If types acquire many of the manipulations that are available for 
data values, then might one find that, in turn, cases will be found that 
seem to require similar capabilities for kinds?

Is there any possibility of a theory that will avoid the need to replicate 
features at higher and higher levels?

(This all seems vaguely reminiscent of the theoretical issues that faced 
denotational program semantics --which I don't claim to understand-- until 
Dana Scott's work showed that there was a logical foundation for treating 
functions as values.  [er, did I get that right?].)

#g
--
Closed classes are certainly interesting, but a better way to go in this
case is to allow the programmer to declear new kinds, as well as new
types.  This is what Tim Sheard's language Omega lets you do, and I'm
considering adding it to GHC.
kind HNat = HZero | HSucc HNat
class HNatC (a::HNat)
instance HNatC HZero
instance HNatC n => HNatC (HSucc n)
Here the keyword 'kind' is like 'data', except that it introduces a new
*kind* HNat with new *type* constructors HZero and HSucc, rather than a
new *type* constructor with new *data* constructors.
There is no way to construct a value of type HZero, or (HSucc HZero);
these are simply phantom types.  Today we are forced to say
data HNat
data HSucc a
which loses the connection between the two.  A merit of declaring a kind
is that the kind is closed -- the only types of kind HNat are HZero,
HSucc HZero, and so on. So the class doesn't need to be closed; no one
can add new instances to HNatC because they don't have any more types of
kind HNat.
At the moment I'm only thinking of parameter-less kind declarations but
one could easily imagine kind parameters, and soon we'll have kind
polymorphism  but one step at a time.
Any thoughts?
Simon
| -Original Message-
| From: [EMAIL PROTECTED]
[mailto:[EMAIL PROTECTED] On Behalf Of
| Duncan Coutts
| Sent: 06 August 2004 15:11
| To: MR K P SCHUPKE
| Cc: Haskell Cafe
| Subject: [Haskell-cafe] closed classes [was: Re: exceptions vs.
Either]
|
| On Fri, 2004-08-06 at 14:05, MR K P SCHUPKE wrote:
| > >You should include the definitions of the classes before saying
| >
| > HOrderedList l' just has to prove by induction that for any element
| > in the list, the next element is greater, so the class is simply:
| >
| > class HOrderedList l
| > instance HNil
| > instance HCons a HNil
| > instance (HOrderedList (HCons b l),HLe a b) => HCons a (HCons b l)
|
| Somewhat off-topic,
|
| It's when we write classes like these that closed classes would be
| really useful.
|
| You really don't want people to add extra instances to this class,
it'd
| really mess up your proofs!
|
| I come across this occasionally, like when modelling external type
| systems. For example the Win32 registry or GConf have a simple type
| system, you can store a fixed number of different primitive types and
in
| the case of GConf, pairs and lists of these primitive types. This can
be
| modelled with a couple type classes and a bunch of instances. However
| this type system is not extensible so it'd be nice if code outside the
| defining module could not interfere with it.
|
| The class being closed might also allow fewer dictionaries and so
better
| run time performance.
|
| It would also have an effect on overlapping instances. In my GConf
| example you can in particular store Strings and lists of any primitive
| type. But now these two overlap because a String is a list. However
| these don't really overlap because Char is not one of the primitive
| types so we could never get instances of String in two different ways.
| But because the class is open the compiler can't see that, someone
could
| always add an instance for Char in another module. If the class w

RE: [Haskell-cafe] closed classes [was: Re: exceptions vs. Either]

2004-08-09 Thread MR K P SCHUPKE
kind statements sound like a good idea - a couple of questions spring to
mind - what is the parameter of a kind statement (a type or a kind... a 
kind makes more sense) ... do we have to stop with kinds what about
"kinds of kinds" - the statement has identical syntax to a data declaration,
is there no way to combine the two, with perhaps a level value?

An example of where you may need kinds-of-kinds (etc) is consider peano numbers
(declared as a kind) ... now consider we have several implementations 
(unary - binary etc) which we wish to group together as an equivalent
to the Num class.

I accept the above is not a good example as this is better served by a class
(as you may well want it 'open')...

It seems from a theoretical point of view easy to add multiple levels of
kinds instead of one level... of course it is probably much more difficault
to do this to GHC?

Of course with kinds of kinds you either have to annotate the statement
with the level - or let the compiler infer the level. The latter seems
much more difficault as the same 'level-less-kind statement' could be
used on multiple levels...

Keean.
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


RE: [Haskell-cafe] closed classes [was: Re: exceptions vs. Either]

2004-08-09 Thread C T McBride
Hi

On Mon, 9 Aug 2004, Simon Peyton-Jones wrote:

> Closed classes are certainly interesting, but a better way to go in this
> case is to allow the programmer to declear new kinds, as well as new
> types.  This is what Tim Sheard's language Omega lets you do, and I'm
> considering adding it to GHC.
>
>   kind HNat = HZero | HSucc HNat
>
>   class HNatC (a::HNat)
>
>   instance HNatC HZero
>   instance HNatC n => HNatC (HSucc n)
>

[..]

> At the moment I'm only thinking of parameter-less kind declarations but
> one could easily imagine kind parameters, and soon we'll have kind
> polymorphism  but one step at a time.
>
> Any thoughts?

Yes. "Yes please."

This is still in the realm of using type-level proxies for values,
but it's a much more practical fake of dependent types than you can
manage with type classes. It lets you do quite a lot of the handy
indexing that's found in basic dependently typed programs, without
quite crossing the line to full-on value dependency. Of course, I
recommend crossing this line in the long run, but I accept that doing
so might well mess things up for GHC. This is a sensible, plausible
step in the right direction. And I'm sure you'll be able to jack it
up to datakinds parametrized by datakinds, provided all the indices
are in constructor form: the unification apparatus you've already got
for datatype families (or GADTs as you've dubbed them) should do
everything you need, as long as you unify the indices before you
unify the indexed `values'.

What you still don't get is the ability to use datatype families to
reflect on values in order to extend pattern matching, the way James
McKinna and I do in `The view from the left'. But one step at a time.
You also don't get for free the ability to write type-level programs
over these things. If you do add type-level programs over datakinds,
you may find that the unification-in-the-typing-rules style comes
under strain. I'm told that's why the ALF crew retreated from full-on
datatype families, which is why they're not in Cayenne. The Epigram
approach is different: the unification problems are solved internally
to the theory, so you still get the solutions when they're easy, but
the wheels don't come off when they're not.

Even so, you do get quite a long way towards the `static' uses of
dependent types which support n-ary vectors and the like, but where
n isn't supposed to be a run-time value. You'll get `projection
from a vector is exception-free'; you won't get `projection from a
vector returns the thing in that position in the vector'.

So let's have this, and we'll see how many of the programs I've
written in the last 5+ years with these data structures become
Haskell programs. More than a few, I expect.

Cheers

Conor
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


RE: [Haskell-cafe] closed classes [was: Re: exceptions vs. Either]

2004-08-09 Thread Simon Peyton-Jones
Closed classes are certainly interesting, but a better way to go in this
case is to allow the programmer to declear new kinds, as well as new
types.  This is what Tim Sheard's language Omega lets you do, and I'm
considering adding it to GHC.

kind HNat = HZero | HSucc HNat

class HNatC (a::HNat)

instance HNatC HZero
instance HNatC n => HNatC (HSucc n)

Here the keyword 'kind' is like 'data', except that it introduces a new
*kind* HNat with new *type* constructors HZero and HSucc, rather than a
new *type* constructor with new *data* constructors.

There is no way to construct a value of type HZero, or (HSucc HZero);
these are simply phantom types.  Today we are forced to say
data HNat
data HSucc a
which loses the connection between the two.  A merit of declaring a kind
is that the kind is closed -- the only types of kind HNat are HZero,
HSucc HZero, and so on. So the class doesn't need to be closed; no one
can add new instances to HNatC because they don't have any more types of
kind HNat.

At the moment I'm only thinking of parameter-less kind declarations but
one could easily imagine kind parameters, and soon we'll have kind
polymorphism  but one step at a time.

Any thoughts?  

Simon


| -Original Message-
| From: [EMAIL PROTECTED]
[mailto:[EMAIL PROTECTED] On Behalf Of
| Duncan Coutts
| Sent: 06 August 2004 15:11
| To: MR K P SCHUPKE
| Cc: Haskell Cafe
| Subject: [Haskell-cafe] closed classes [was: Re: exceptions vs.
Either]
| 
| On Fri, 2004-08-06 at 14:05, MR K P SCHUPKE wrote:
| > >You should include the definitions of the classes before saying
| >
| > HOrderedList l' just has to prove by induction that for any element
| > in the list, the next element is greater, so the class is simply:
| >
| > class HOrderedList l
| > instance HNil
| > instance HCons a HNil
| > instance (HOrderedList (HCons b l),HLe a b) => HCons a (HCons b l)
| 
| Somewhat off-topic,
| 
| It's when we write classes like these that closed classes would be
| really useful.
| 
| You really don't want people to add extra instances to this class,
it'd
| really mess up your proofs!
| 
| I come across this occasionally, like when modelling external type
| systems. For example the Win32 registry or GConf have a simple type
| system, you can store a fixed number of different primitive types and
in
| the case of GConf, pairs and lists of these primitive types. This can
be
| modelled with a couple type classes and a bunch of instances. However
| this type system is not extensible so it'd be nice if code outside the
| defining module could not interfere with it.
| 
| The class being closed might also allow fewer dictionaries and so
better
| run time performance.
| 
| It would also have an effect on overlapping instances. In my GConf
| example you can in particular store Strings and lists of any primitive
| type. But now these two overlap because a String is a list. However
| these don't really overlap because Char is not one of the primitive
| types so we could never get instances of String in two different ways.
| But because the class is open the compiler can't see that, someone
could
| always add an instance for Char in another module. If the class were
| closed they couldn't and the compiler could look at all the instances
in
| deciding if any of them overlap.
| 
| So here's my wishlist item:
| 
| closed class GConfValue v where
|  ...
| 
| Duncan
| 
| ___
| Haskell-Cafe mailing list
| [EMAIL PROTECTED]
| http://www.haskell.org/mailman/listinfo/haskell-cafe
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


[Haskell-cafe] closed classes [was: Re: exceptions vs. Either]

2004-08-06 Thread Duncan Coutts
On Fri, 2004-08-06 at 14:05, MR K P SCHUPKE wrote:
> >You should include the definitions of the classes before saying
> 
> HOrderedList l' just has to prove by induction that for any element
> in the list, the next element is greater, so the class is simply:
> 
> class HOrderedList l
> instance HNil
> instance HCons a HNil
> instance (HOrderedList (HCons b l),HLe a b) => HCons a (HCons b l)

Somewhat off-topic,

It's when we write classes like these that closed classes would be
really useful.

You really don't want people to add extra instances to this class, it'd
really mess up your proofs!

I come across this occasionally, like when modelling external type
systems. For example the Win32 registry or GConf have a simple type
system, you can store a fixed number of different primitive types and in
the case of GConf, pairs and lists of these primitive types. This can be
modelled with a couple type classes and a bunch of instances. However
this type system is not extensible so it'd be nice if code outside the
defining module could not interfere with it.

The class being closed might also allow fewer dictionaries and so better
run time performance.

It would also have an effect on overlapping instances. In my GConf
example you can in particular store Strings and lists of any primitive
type. But now these two overlap because a String is a list. However
these don't really overlap because Char is not one of the primitive
types so we could never get instances of String in two different ways.
But because the class is open the compiler can't see that, someone could
always add an instance for Char in another module. If the class were
closed they couldn't and the compiler could look at all the instances in
deciding if any of them overlap.

So here's my wishlist item:

closed class GConfValue v where
 ...

Duncan

___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe