RE: Exceptions

2006-09-04 Thread Simon Marlow
On 02 September 2006 06:29, Ashley Yakeley wrote:

 I'd also like to query O'Haskell here. Simon writes in the paper:
 
 O'Haskell extends Haskell with object-oriented subtyping.
 As such, it would be entirely possible to implement extensible
 exceptions using inheritance in O'Haskell.
 
 I believe O'Haskell (like OOHaskell) doesn't provide the required
 dynamic downcasting operation either. AFAICT the extensions are
 essentially syntactic sugar: the subtyping is strictly static.

Good point; thanks for spotting that.

Simon
___
Haskell-prime mailing list
Haskell-prime@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-prime


Re: Exceptions

2006-09-01 Thread Andres Loeh
Hi Ashley.

Thanks for your interest in open data types. As one of the authors of
the open data types paper, I'd like to comment on the current
discussion.

You comment Simon's upcoming HW paper on extensible exceptions:

 You write:
 
  Compared to our approach, theirs requires new extensions to the language 
  (although not deep),
 
 Typeable is an extension to Haskell, and a rather ugly one at that. 
 The open datatypes extension is both cleaner and more general.

I think the stress here is on *new* extensions. I agree that an open
type of type representations might be a more beautiful solution to the
problem that Typeable solves. Nevertheless, the fact is that Simon's
solution can be used in current GHC without further implementation work.

  and has difficulties with separate compilation.
 
 They claim to solve this I think, though I haven't examined it really 
 carefully. You may know better, of course.

I've discussed this with Simon PJ. Apart from minor technical problems,
everything seems doable in GHC, but it is quite some work and it's not clear
that I will have the time to study GHC closely enough to do it in the
near future. I hope I can say more after the Hackathon ...

  Arguably the open data types approach is more direct and more accessible,
 
 Yes,
 
  as is often the case with extensions designed to solve a particular problem.
 
 That's not fair. Open datatypes have other applications. A general file 
 interpreter for instance, that given a MIME type string and a list of 
 bytes yields an object. Or a collection of variable resources of 
 various types that could be passed to a program. Or a hierarchy of UI 
 widgets. Or anything that Typeable and Dynamic are currently used for, 
 but more cleanly. Hs-plugins, for instance.
 
 It's the missing piece.

True, open data types have never been invented as a solution to the
problem of extensible exceptions. It is an application that we found
afterwards.

  Still, the argument for adding open data types to the language is weakened 
  by 
  the fact that they are subsumed by type classes: in fact the authors give 
  an 
  encoding of open data types into type classes,
 
 Well not really. The encoding involves lifting everything from values 
 to types, which means a function still can't return a value of an open 
 type determined at run-time.

Even if both approaches would be equally expressive, the type class encoding
still has a lot of syntactic overhead. Moving from a closed to an open data
type encoded by type classes requires changing your whole program, whereas
with open data types, it is a local change.

Apart from this discussion however, open data types are clearly not
Haskell' material, because the proposal is new and currently
unimplemented.

The extensions required for Simon's approach to exceptions have a good
chance of being included in Haskell'.

Cheers,
  Andres
___
Haskell-prime mailing list
Haskell-prime@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-prime


Re: Exceptions

2006-09-01 Thread Ashley Yakeley
In article [EMAIL PROTECTED],
 Andres Loeh [EMAIL PROTECTED] wrote:

 I think the stress here is on *new* extensions. I agree that an open
 type of type representations might be a more beautiful solution to the
 problem that Typeable solves. Nevertheless, the fact is that Simon's
 solution can be used in current GHC without further implementation work.

OK, fair enough. Open datatypes and functions will not, as you point 
out, be in Haskell'.

I'd also like to query O'Haskell here. Simon writes in the paper:

 O'Haskell extends Haskell with object-oriented subtyping.
 As such, it would be entirely possible to implement extensible
 exceptions using inheritance in O'Haskell.

I believe O'Haskell (like OOHaskell) doesn't provide the required 
dynamic downcasting operation either. AFAICT the extensions are 
essentially syntactic sugar: the subtyping is strictly static.

-- 
Ashley Yakeley, Seattle WA

___
Haskell-prime mailing list
Haskell-prime@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-prime


RE: Exceptions

2006-08-31 Thread Simon Marlow
On 30 August 2006 20:20, Ashley Yakeley wrote:

 John Goerzen wrote:
 
 One thing that bugs me about Haskell is that exceptions are not
 extensible. 
 
 I don't know how to craft a good solution, but perhaps if I explain
 the problem well, someone would come up with one.
 
 Open datatypes would be the best solution, I think.
http://www.informatik.uni-bonn.de/~loeh/OpenDatatypes.pdf

I don't think we need more extensions to do a reasonable job of
extensible exceptions:

http://www.haskell.org/~simonmar/papers/ext-exceptions.pdf

Cheers,
Simon
___
Haskell-prime mailing list
Haskell-prime@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-prime


Re: Exceptions

2006-08-31 Thread Ashley Yakeley
In article 
[EMAIL PROTECTED]
ft.com,
 Simon Marlow [EMAIL PROTECTED] 
 wrote:

 I don't think we need more extensions to do a reasonable job of
 extensible exceptions:
 
 http://www.haskell.org/~simonmar/papers/ext-exceptions.pdf

You write:

 Compared to our approach, theirs requires new extensions to the language 
 (although not deep),

Typeable is an extension to Haskell, and a rather ugly one at that. 
The open datatypes extension is both cleaner and more general.

 and has difficulties with separate compilation.

They claim to solve this I think, though I haven't examined it really 
carefully. You may know better, of course.

 Arguably the open data types approach is more direct and more accessible,

Yes,

 as is often the case with extensions designed to solve a particular problem.

That's not fair. Open datatypes have other applications. A general file 
interpreter for instance, that given a MIME type string and a list of 
bytes yields an object. Or a collection of variable resources of 
various types that could be passed to a program. Or a hierarchy of UI 
widgets. Or anything that Typeable and Dynamic are currently used for, 
but more cleanly. Hs-plugins, for instance.

It's the missing piece.

 Still, the argument for adding open data types to the language is weakened by 
 the fact that they are subsumed by type classes: in fact the authors give an 
 encoding of open data types into type classes,

Well not really. The encoding involves lifting everything from values 
to types, which means a function still can't return a value of an open 
type determined at run-time.

-- 
Ashley Yakeley
Seattle WA

___
Haskell-prime mailing list
Haskell-prime@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-prime


Re: Exceptions

2006-08-30 Thread Ashley Yakeley

John Goerzen wrote:


One thing that bugs me about Haskell is that exceptions are not
extensible.

I don't know how to craft a good solution, but perhaps if I explain the
problem well, someone would come up with one.


Open datatypes would be the best solution, I think.
  http://www.informatik.uni-bonn.de/~loeh/OpenDatatypes.pdf

--
Ashley Yakeley
Seattle, WA

___
Haskell-prime mailing list
Haskell-prime@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-prime


RE: Exceptions

2006-04-11 Thread Simon Marlow
Attached is another variant of the extensible exceptions idea, it
improves on the previous designs in a couple of ways:  there's only one
catch  throw, regardless of what type you're throwing or catching.
There is an extensible hierarchy of exceptions, and you can catch and
re-throw subclasses of exceptions.

So this design contains a dynamically-typed extensible hierarchy, but
it's fairly lightweight.  Adding a new leaf exception type requires 3
lines + 1 line for each superclass (just 1 line for a top level leaf, as
before).  Adding a new node requires about 10 lines + 1 line for each
superclass, msotly boilerplate.

Perhaps the type class hackers can do better than this!

Cheers,
Simon


Exception-2.hs
Description: Exception-2.hs
___
Haskell-prime mailing list
Haskell-prime@haskell.org
http://haskell.org/mailman/listinfo/haskell-prime


Re: Exceptions

2006-04-11 Thread John Meacham
On Tue, Apr 11, 2006 at 01:24:07PM +0100, Simon Marlow wrote:
 Attached is another variant of the extensible exceptions idea, it
 improves on the previous designs in a couple of ways:  there's only one
 catch  throw, regardless of what type you're throwing or catching.
 There is an extensible hierarchy of exceptions, and you can catch and
 re-throw subclasses of exceptions.

I made the catch and throw separate so the decision as to whether to
include imprecice exceptions and extensible extensions can be made
independently.  

that and

throw x /= ioError x

ioError x  return ()  - IO _|_  (only _|_ when IO action executed)
throw x  return () - _|_

ioError x `seq` ()  - ()
throw x `seq` () - _|_

John

-- 
John Meacham - ⑆repetae.net⑆john⑈
___
Haskell-prime mailing list
Haskell-prime@haskell.org
http://haskell.org/mailman/listinfo/haskell-prime


Re: Exceptions

2006-04-11 Thread John Meacham
On Tue, Apr 11, 2006 at 05:35:12AM -0700, John Meacham wrote:
 throw x  return () - _|_

hmm.. actually is this true? hmm.. seq and IO always mixed oddly.

John

-- 
John Meacham - ⑆repetae.net⑆john⑈
___
Haskell-prime mailing list
Haskell-prime@haskell.org
http://haskell.org/mailman/listinfo/haskell-prime


RE: Exceptions

2006-04-11 Thread Simon Marlow
On 11 April 2006 13:35, John Meacham wrote:

 On Tue, Apr 11, 2006 at 01:24:07PM +0100, Simon Marlow wrote:
 Attached is another variant of the extensible exceptions idea, it
 improves on the previous designs in a couple of ways:  there's only
 one catch  throw, regardless of what type you're throwing or
 catching. There is an extensible hierarchy of exceptions, and you
 can catch and re-throw subclasses of exceptions.
 
 I made the catch and throw separate so the decision as to whether to
 include imprecice exceptions and extensible extensions can be made
 independently.
 
 that and
 
 throw x /= ioError x
 
 ioError x  return ()  - IO _|_  (only _|_ when IO action executed)
 throw x  return () - _|_
 
 ioError x `seq` ()  - ()
 throw x `seq` () - _|_

yes, when I say one throw I was referring to the argument type, not
the return type.  We should still have ioError - although it would
probably be better named throwIO:

http://www.haskell.org/ghc/docs/latest/html/libraries/base/Control-Excep
tion.html#v%3AthrowIO

(the docs for throwIO also mention the strictness property you described
above)

Cheers,
Simon
___
Haskell-prime mailing list
Haskell-prime@haskell.org
http://haskell.org/mailman/listinfo/haskell-prime


Re: Exceptions

2006-04-11 Thread John Meacham
On Tue, Apr 11, 2006 at 01:43:18PM +0100, Simon Marlow wrote:
 yes, when I say one throw I was referring to the argument type, not
 the return type.  We should still have ioError - although it would
 probably be better named throwIO:

Ah, I see what you mean now.

would it be possible to use Typeable1 to just catch 'ArithException a'
for any Typeable a? It seems like it should be, but I have not used
Typeable1 much.


John

-- 
John Meacham - ⑆repetae.net⑆john⑈
___
Haskell-prime mailing list
Haskell-prime@haskell.org
http://haskell.org/mailman/listinfo/haskell-prime


RE: Exceptions

2006-04-11 Thread Simon Marlow
On 11 April 2006 13:54, John Meacham wrote:

 On Tue, Apr 11, 2006 at 01:43:18PM +0100, Simon Marlow wrote:
 yes, when I say one throw I was referring to the argument type, not
 the return type.  We should still have ioError - although it would
 probably be better named throwIO:
 
 Ah, I see what you mean now.
 
 would it be possible to use Typeable1 to just catch 'ArithException a'
 for any Typeable a? It seems like it should be, but I have not used
 Typeable1 much.

I tried it briefly and couldn't get it to work, but I'm no expert on the
SYB stuff.  You might need an Exception1 class to go with Typeable1, and
that would be fairly ugly.

Cheers,
Simon
___
Haskell-prime mailing list
Haskell-prime@haskell.org
http://haskell.org/mailman/listinfo/haskell-prime


Re: Exceptions

2006-04-08 Thread Dave Menendez
John Meacham writes:

 On Fri, Apr 07, 2006 at 10:00:21AM -0500, John Goerzen wrote:
  But here's my concern.  Let's say that I wanted to, for some
  reason, create a MultiplyByZero exception.  It should be broadly
  considered an ArithException, and any code that catches an
  ArithException should be able to catch my MultiplyByZero exception.
  
  But the ArithException type is limited to storing errors that are
  defined by Control.Exception.ArithException.  My MultiplyByZero is
  not defined there, so I am out of luck.  The best I could do is
  define a new MultiplyByZero, and catch it in my own code.  But any
  code that others have written to catch ArithExceptions would be
  blind to MultiplyByZero.
 
 newtype ArithException a = ArithException a
 
 data DivideByZero
 
 throw (ArithException DivideByZero)
 
 your code:
 
 data MultiplyByZero
 throw (ArithException MultiplyByZero)

How would you use this to write a handler that captures any
ArithException?
-- 
David Menendez [EMAIL PROTECTED] | In this house, we obey the laws
http://www.eyrie.org/~zednenem  |of thermodynamics!
___
Haskell-prime mailing list
Haskell-prime@haskell.org
http://haskell.org/mailman/listinfo/haskell-prime


[Haskell] Re: Exceptions

2004-11-23 Thread John Goerzen
On 2004-11-23, Johannes Waldmann [EMAIL PROTECTED] wrote:
 in the following example, the handler won't catch the exception
 because of lazy evaluation. therefore, it's a different story
 than with exceptions in ML, Python, whatever strict language.

 main = do
  xs - return [ 1, 2, error throw ]
  `catch` \ any - do
  putStrLn caught
   return [ 4, 5, 6 ]
  print xs

That didn't quite compile as-is; I assume you ment:

main = do
 xs - return [ 1, 2, error throw ]
 `catch` \ any - do
 putStrLn caught
 return [ 4, 5, 6 ]
 print xs

When run, I get: Fail: throw

In any case, in the more general case, I don't see a problem with that.
I get an exception when I try to use something.  That's fine.  In an
imperative program that solves the same problem the same way, you'd see
the exception at the same point.


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


Re: [Haskell] Re: Exceptions

2004-11-23 Thread Ben Rudiak-Gould
John Goerzen wrote:
main = do
 xs - return [ 1, 2, error throw ]
 `catch` \ any - do
 putStrLn caught
 return [ 4, 5, 6 ]
 print xs

When run, I get: Fail: throw

In any case, in the more general case, I don't see a problem with that.
I get an exception when I try to use something.  That's fine.  In an
imperative program that solves the same problem the same way, you'd see
the exception at the same point.
No, in a traditional (strict) programming language the program would print
   caught
   [4,5,6]
The exception throw would not appear in the output.
-- Ben
___
Haskell mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell


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 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
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 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 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
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-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 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 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 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 anything'
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


[Haskell-cafe] Re: exceptions vs. Either

2004-08-06 Thread MR K P SCHUPKE
After all, Java basically does exactly what you're asking for with

Java's head/tail would be doing runtime checks if they are throwing exceptions,
static guarantees mean the program would not be allowed to compile if it broke
the static guarantees.

end-programmers have to worry much less about handling errors properly.

Which is a bad thing! All programmers always have to consider error conditions,
if they don't they write buggy code - that's the nature of the beast. I prefer
making programmers expicitly face the decisions they are making, rather than
have things implicitly handled in a way that hides what is going on from the
programmer.

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


Re: [Haskell-cafe] Re: exceptions vs. Either

2004-08-06 Thread Keith Wansbrough
 After all, Java basically does exactly what you're asking for with
 
 Java's head/tail would be doing runtime checks if they are throwing exceptions,
 static guarantees mean the program would not be allowed to compile if it broke
 the static guarantees.

Not so.  In Java, the programmer is forced to handle most exceptions
by the type system.  That is, if the exception is not handled, the
program will not compile, thus providing a static guarantee that
exceptions are handled.

Only unchecked exceptions (RuntimeException and Error) are exempt
from this check.

--KW 8-)

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


Re: [Haskell-cafe] Re: exceptions vs. Either

2004-08-06 Thread MR K P SCHUPKE
Not so.  In Java, the programmer is forced to handle most exceptions

I forgot you had to do that... Exceptions are explicit in the type
signatures. I think Oleg posted a message a while back about how to
make exceptions explicit in haskell type signatures... But I would
rather use static guarantees where possible, and exceptions where
necessary. I haven't really tried using the techniques for explicit
exceptions, but on consideration I might see if it is practical to
code in that style...

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


Re: [Haskell-cafe] Re: exceptions vs. Either

2004-08-06 Thread MR K P SCHUPKE
Static guarantees are great, but if you have to explicitly change your
style of coding to cope with those extra constraints, it can become (very)
cumbersome.

I had to change coding style moving from imperative to declarative languages,
but I think it was worth it... Likewise I think having the ability to make
strong static guaranees is worth it - you may not, which is why it is 
important not to break any existing programs with language extensions
(if any are necessary). My programs will have less bugs though!

worse-is-better, even in its strawman form, has better survival

I fully subscribe to the 'worse is better' approach, but I don't see
how it contradicts the principle of static guarantees - you can have
both. Simplicity is about algorithmic complexity not about whether
type signatures are provided by the programmer. Infact type
signatures are in themselves an embodyment of the simple is better
principle. A type signature expresses certain static guarantees about
the function in a vary compact way. Consider the sort example...
being able to declare a type signature on a sort algorith that enforces
ordering of the output would prove the sort algorithm can _only_ output
correctly sorted lists under _all_ circunstances. This type signature
is much simpler than the actual sort - hence is useful.

sort :: (HList l,HOrderedList l') = l - l'

Nice and readable, and much simpler than the actual algorithm (be
it bubble sort, or a quick sort)

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


Re: [Haskell-cafe] Re: exceptions vs. Either

2004-08-06 Thread Keith Wansbrough
 correctly sorted lists under _all_ circunstances. This type signature
 is much simpler than the actual sort - hence is useful.
 
   sort :: (HList l,HOrderedList l') = l - l'
 
 Nice and readable, and much simpler than the actual algorithm (be
 it bubble sort, or a quick sort)

The type signature you give is no different from

sort :: (C1 l, C2 l') = l - l'

and conveys no more information.  You should include the definitions
of the classes before saying this is much simpler than the actual
sort.

--KW 8-)

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


Re: [Haskell-cafe] Re: exceptions vs. Either

2004-08-06 Thread MR K P SCHUPKE
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)

which is the equivalent type level program to  

ordered :: [Int] - Bool
ordered [] = True
ordered [a] = True
ordered (a:(b:l)) = if a=b then ordered (b:l) else False
ordered _ = False

It is obvious by observation that the a=b ensures order.
This is a lot simpler than say a heap-sort.   

I suppose you could contend that there are some classes above
I still haven't defined - but you wouldn't expect to see definitions
for (=) which is defined in the prelude. Of course to show statically
that order is preserved the 'value' of the elements to be ordered must
be visible to the type system - so the values must be reified to types...
This can be done for any Haskell type, but for numbers we would
use Peano numbers - the HLe class for these is again easily defined
by induction:

class HLe n n' 
instance HLe HZero HZero
instance HLe x y = HLe (HSucc x) (HSucc y)


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-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


[Haskell-cafe] Re: exceptions vs. Either

2004-08-06 Thread André Pang
On 06/08/2004, at 6:56 PM, MR K P SCHUPKE wrote:
After all, Java basically does exactly what you're asking for with
Java's head/tail would be doing runtime checks if they are throwing 
exceptions,
static guarantees mean the program would not be allowed to compile if 
it broke
the static guarantees.
As Keith said, Java will check at compile time whether or not you 
handle the exception.  My point is this: it is impossible to check 
whether the exception is properly handled.  If you adjust Haskell's 
tail function to return (Maybe [a]) instead of just ([a]), you are 
doing the thing as Java from a pragmatic perspective: you are adding 
information to the type system that tells the programmer the function 
may fail.  You also suffer the same consequence as Java: you have no 
idea whether the programmer properly handles the error situation.

If I am writing a one-shot, never-use-again script that takes 3 minutes 
to write, and I _know_ that I'm not going to be feeding the tail 
function a non-empty list--e.g. because I'm writing a one-shot 
five-minute script to transform a file from one text format to another, 
as is the case for lots of Perl programs--then the extra Maybe type 
just gets in the way.  I'll either ignore the Nothing case, or write 
`case tail foo of ... Nothing - error bleh'.  I will go so far to 
say that such a program can be considered correct: it does exactly 
what I want it to do, in exactly the circumstances I desire (0 byte 
files being specifically excluded from the circumstances!).

Which is a bad thing! All programmers always have to consider error 
conditions,
if they don't they write buggy code - that's the nature of the beast. 
I prefer
making programmers expicitly face the decisions they are making, 
rather than
have things implicitly handled in a way that hides what is going on 
from the
programmer.
It's a question of whether the library designer should impose their 
will on the library user.  As a library designer, do you feel that you 
are always making the right decision for the library user 100% of the 
time?  I know I never feel like that when I write libraries ...

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


[Haskell-cafe] Re: exceptions vs. Either

2004-08-05 Thread MR K P SCHUPKE
What can I say... Static typing guarantees is what made me switch from
object oriented languages like C++/ObjectiveC/Java (that and the availability
of a good compiler) - So I am obviously in favour of more static guarantees -
I believe programming by contract is the way to reliable _engineered_ software,
so the more contractual obligations that can be concisely and clearly expressed
in the type system the better. I think Haskell should support dependant types,
after all if you don't want to use them you don't have to... (backwards compatability
and all that) although it would be useful to have a replacement prelude that 
used dependant types versions of head etc...

I have a hard time understanding why functional programmers would not want
more static typing guarantees, after all they can always use C if they
dont like type systems!

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


Re: [Haskell-cafe] Re: exceptions vs. Either

2004-08-05 Thread Alastair Reid

 I have a hard time understanding why functional programmers
 would not want more static typing guarantees, after all they
 can always use C if they dont like type systems!

I think the value of Haskell's type system is that it catches a lot of bugs 
_cheaply_.  That is, with little programmer effort to write the type 
annotations, little effort to understand them and little effort to maintain 
them as the program evolves.

In general, as we try to express more and more in the type system, the costs 
go up so the goal in using a different programming style or extending the 
type system is to catch more bugs without significantly increasing the cost.  
At an extreme, we could probably use some variant of higher order predicate 
calculus as our type system and specify that a sort function (say) returns an 
ordered list but the programmer effort in doing so would probably be quite 
high.

Using Maybe and the like to catch more errors with the type system isn't as 
expensive as using full-on specification and is often the right thing to do 
but, in some cases, the benefits of programming that way don't justify the 
effort required whereas the techniques suggested for reporting the location 
of the problem are cheap and effective.

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


Re: [Haskell-cafe] Re: exceptions vs. Either

2004-08-05 Thread Conor T McBride
Hi folks
Alastair Reid wrote:
I have a hard time understanding why functional programmers
would not want more static typing guarantees, after all they
can always use C if they dont like type systems!

 I think the value of Haskell's type system is that it catches a lot 
of  bugs _cheaply_.  That is, with little programmer effort to write the
 type annotations, little effort to understand them and little effort
 to maintain them as the program evolves.

I entirely agree. The effort-to-reward ratio is the key consideration
when deciding how much information to build into types. I'm biased, of
course, but the thing I like about working with a dependent type system
is that I at least have the option to explore a continuum of static
expressivity and choose a compromise which suits my conception of the
task at hand. To oppose the availability of more informative types is to
rule out the option of exploiting them even when they are useful.
A key aspect of the Epigram approach is to pay attention to the
/tools/ we use to write programs. Of course it gets harder to work with
more involved types if you have to do it all in your head.
Frankly, polymorphic recursion is enough to make my brain hurt, let
alone the kind of type class shenanigans which various people (myself
included) have been engaging in. I have a not-so-secret weapon. Once
I've developed the program interactively in Epigram (or its predecessor,
OLEG, in the case of the Faking It stuff), exploiting the fact that
a computer can push type information /into/ the programming process,
it's quite easy to crank out the relevant steaming lump of obfuscated
Haskell.
One tool that's really needed here is a refactoring editor which
enables you to write the program naively, exposing the exceptional
cases, then, once you've seen where they show up, refine the data
structures to eliminate some or all of them. It's a fair cop: at the
moment, Epigram requires you to dream up the data structures from thin
air before you write the programs. That doesn't fit with the fact that
good ideas only tend to come a bit at a time. However, we can certainly
improve on this situtation, given time and effort.
 In general, as we try to express more and more in the type system, the
 costs go up so the goal in using a different programming style or
 extending the type system is to catch more bugs without significantly
 increasing the cost.  At an extreme, we could probably use some
 variant of higher order predicate calculus as our type system
I'd recommend a system which enables you to build stronger structural
invariants directly into data structures, rather than using data
types which are too big, and then a whole pile of predicates to cut
them down to size afterwards: as you fear, the latter is a good way
to fill a program up with noisy proofs. But if you use indexed datatype
families (Dybjer, 1991), you can avoid a lot of this mess and what's
more, a type-aware editor can rule out many exceptional cases on your
behalf. In many cases, the Epigram editor shows you exactly the data
which are consistent with the invariants, without any effort on your
part.
 and specify that a sort function (say) returns an
 ordered list but the programmer effort in doing so would probably be
 quite high.
I'm pleased to say it isn't. See
  http://www.dur.ac.uk/c.t.mcbride/a-case/
and in particular
  http://www.dur.ac.uk/c.t.mcbride/a-case/16so/
onwards, for treesort-enforcing-sorted-output. There's not much to it,
really. The thing is, ordinary if-then-else loses the fact that
performing the comparisons directly establishes the properties required
to satisfy the sorting invariants in the output structures. It's not
hard to remedy this situation. Moreover, most of the logical plumbing
can be managed implicitly, as it merely requires picking up proofs
which are immediately visible in the context. Of course, (see
Inductive Families Need Not Store Their Indices, by Edwin Brady, James
McKinna and myself) none of this logical stuff incurs any run-time
overhead.
 Using Maybe and the like to catch more errors with the type system
 isn't as expensive as using full-on specification and is often the
 right thing to do but, in some cases, the benefits of programming that
 way don't justify the effort required whereas the techniques suggested
 for reporting the location of the problem are cheap and effective.
You're absolutely right. And today's technology often means that the
match-exception way, let alone the Maybe-way, wins this trade-off.
Tomorrow's technology will not remove this trade-off, but it might
sometimes change the outcome of the calculation. I think that's worth
working for.
Cheers
Conor
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: exceptions vs. Either

2004-08-05 Thread MR K P SCHUPKE
specify that a sort function (say) returns an ordered list

Fistly this is already possible in Haskell - see Oleg, Ralf and
My paper: 

@misc{KLS04,
 author = Oleg Kiselyov and Ralf L{\a}mmel and Keean Schupke,
 title = {Strongly typed heterogeneous collections},
 booktitle = {ACM SIGPLAN Workshop on Haskell},
 year = 2004,
 month = sep,
 publisher = ACM Press,
 notes = To appear
}

http://homepages.cwi.nl/~ralf/HList/

Here we show constrained heterogeneous lists (but you can also 
constrain the type in the list to turn it into a homogeneous list)
that includes the ability to impose ordering constraints...

Writing the constraint classes is a little involved but using it is
as simple as:

sort :: (HList l,HOrderedList l') = l - l'

and supposing you dont like having to write the complete type, you
can use:

ordered :: HOrderedList l = l - l
ordered = id

then you can use this in a function with no type given:

sort = ordered . sort'


So my point is this can be added to haskell _without_ breaking
any existing functionality - it is not either/or it is both/and!

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


[Haskell-cafe] Re: exceptions vs. Either

2004-08-05 Thread André Pang
On 05/08/2004, at 7:40 PM, MR K P SCHUPKE wrote:
I have a hard time understanding why functional programmers would not 
want
more static typing guarantees, after all they can always use C if they
dont like type systems!
Static guarantees are great, but if you have to explicitly change your 
style of coding to cope with those extra constraints, it can become 
(very) cumbersome.

After all, Java basically does exactly what you're asking for with 
head/tail: if you were to write a tail method in a List class, you 
could simply throw a EmptyListException.  That's really the same effect 
as tail in Haskell returning a Maybe: both forms force you to perform 
error-handling in the calling function.  However, I think Java has 
shown that forcing error-handling on the caller via exceptions is no 
magic bullet: a lazy programmer will simply catch the exception in an 
empty catch {} block.  It's a human problem, not a technical one.

Obviously exceptions, Maybes, monads etc. are useful, but forcing the 
programmer to Do The Right Thing is nearly impossible.  I personally 
think that using tricks such as type classes to propagate constraints 
and errors via the type system is a fantastic idea, because then 
end-programmers have to worry much less about handling errors properly.

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


[Haskell-cafe] Re: exceptions vs. Either

2004-08-04 Thread André Pang
On 04/08/2004, at 12:28 AM, MR K P SCHUPKE wrote:
f (case xs of (x:_) - x; [] - error whoops)  -- direct style
Yup, this is how I do it... I never use head!
I like to pass failures back up to the level where some kind of 
sensible
error message can be generated. In your example the error is no
better than with 'head' - the point is a Nothing can be 'caught'
outside of an IO monad.

I would suggest using the type system as I said earlier so:
toNonEmptyList :: [a] - Maybe (NonEmpty a)
toNonEmptyList (a0:_) = Just (NonEmpty a)
toNonEmptyList _ = Nothing
Then redefine head:
head :: NonEmpty a - a
head (NonEmpty (a0:_)) = a0
There's an interesting discussion going on at Lambda the Ultimate right 
now, about this very topic:

http://lambda-the-ultimate.org/node/view/157#comment
There are plenty of noteworthy comments there, but one which quite 
nicely expresses my point of view is:

Using Maybe for this is like saying - let's turn this partial 
function into a total one by lifting its range to include Nothing. It 
became total by obtaining permission to return something I have no use 
of. I do not say monads are not useful, or Maybe is not useful.

And, of course, there's the type wizardry post by Oleg:
http://lambda-the-ultimate.org/node/view/157#comment-1043
I'd like to point out that it is possible in Haskell98 to write 
non-trivial list-processing programs that are statically assured of 
never throwing a `null list' exception. That is, tail and head are 
guaranteed by the type system to be applied only to non-empty lists. 
Again, the guarantee is static, and it is available in Haskell98. 
Because of that guarantee, one may use implementations of head and tail 
that don't do any checks. Therefore, it is possible to achieve both 
safety and efficiency. Please see the second half of the following 
message:

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


RE: exceptions

2003-07-30 Thread Simon Marlow
 
 just out of curiosity, which is the proper idiom?
 
 trace a  = r - catch a (\e - putStr exceptional\n  throw e)
 trace a  = r - catch a (\e - putStr exceptional\n  ioError e)
 
 I am worried that one might subtly change the semantics of an 
 execption
 depending on how it was originally thrown... but i am uncertain how.
 probably some obscure case involving bottoms. But to be on the safe
 side, thought I'd ask.

The second is more correct, if you're using Prelude.catch.  If you're
using Control.Exception.catch, then you want throwIO instead of ioError.

The difference between throw and ioError is this:

  seq (throw e)   E  ==  throw e
  seq (ioError e) E  ==  E

Cheers,
Simon

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


Re: Exceptions with Hugs 98

2002-09-19 Thread Alastair Reid


juan albornoz [EMAIL PROTECTED] writes:
 Hello I need to catch some exceptions which I've thrown with the
 error function. I am using WinHugs 98. Can any one help me?

Something along the lines of:

  import qualified Exception as E

  foo = E.catch mumble (\e - print e)

should do you.

See the papers on exception handling:

  http://www.reid-consulting-uk.ltd.uk/alastair/publications/except-pldi.ps.gz

and the documentation for the library 

  http://www.haskell.org/ghc/docs/latest/html/base/Control.Exception.html

(This is GHC documentation but the Hugs library is mostly compatible.
The main differences are in things not covered by the original paper -
see the (quite readable) source code for the Hugs version of Exception
for details.)

--
Alastair Reid [EMAIL PROTECTED]  
Reid Consulting (UK) Limited  http://www.reid-consulting-uk.ltd.uk/alastair/

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



Re: Exceptions and sockets

2001-05-02 Thread Volker Stolz

In local.glasgow-haskell-users, you wrote:
I `Socket.accept' a connection and get a handle.
Now, if the connections dies, but I still write to the handle,
the whole thing crashes - without throwing an exception.
(I checked that the RTS thinks  `hIsWritable h'
even if `h' does no longer exist in reality.)

Looks to me like you're forgetting that the OS will give you a
sigPIPE on (semi-)closed sockets, which translates to a segfault
unless you install a signal handler:

 - http://www.haskell.org/ghc/docs/latest/set/socket.html#AEN13989
 - socket(2)
-- 
Abstrakte Syntaxträume.
Volker Stolz * [EMAIL PROTECTED] * PGP + S/MIME

___
Glasgow-haskell-users mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users



Re: Exceptions

2000-11-14 Thread Reuben Thomas

 I just installed ghc-4.08.1 on a Win2k computer. Then I tried to compile a 
 program that uses exceptions. Compilation succeeds, but running the program 
 causes a "Application Error" dialog to appear. It says "The application 
 failed to initialize properly (0xc005). Click on OK to terminate the 
 application.". Here is the Haskell program:
 
 --
 module Main(main) where
 
 import Exception
 
 main = catchAllIO (putStrLn (head ([] :: [String])))
(\e - putStrLn "hi" )
 
 --
 
 Compiled it with
 
 ghc-4.08.1 -i/apps/ghc/lib/imports/lang -syslib lang Main.hs

This should be OK, but as Christian Lescher says, you can just say "-package
lang" rather than all the gumph you have.

The error message looks like a fairly typical Windows RTS problem. It could
be that I just missed something in my recent round of fixes. I'm afraid I'm
away at a DevLab in Redmond at the moment, so I'll check it next week when I
return. The only thing I can suggest for now is to reinstall GHC unless you
really have *just* installed it; I updated the InstallShield on about
November 6th.

-- 
http://sc3d.org/rrt/ | competent, a.  underpromoted


___
Glasgow-haskell-bugs mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs



Re: Exceptions and functions. Second round?

1998-06-17 Thread Fergus Henderson

On 16-Jun-1998, Greg Michaelson [EMAIL PROTECTED] wrote:
 In SML(sorry...), in: exp1 handle exp2
 exp1 is evaluated and any exception raised within it is handled by an
 appropriate handler in exp2. If there isn't one then the exception
 is handled in the enclosing environment for the whole construct. Similarly,
 if an exception is raised in exp2 then it is handled in the enclosing
 environment. So exception handling follows a stack based regime.
 
 Instead, how about having exp2 handle exceptions raised within itself 

You can do this quite easily:

expr1 `recursive_handle` expr2 =
expr1 `handle` (\ e - expr2 e `recursive_handle` expr2)

(Here I'm using a version of `handle' where the handler is the 2nd argument.)

However, doing this might be a bad idea, I think, because if `expr2'
raises any exception, this could easily lead to an infinite loop.

 and also allowing mutually recursive handlers?

This is also allowed by the current proposal -- it's quite straightforward:

handler1 e = stuff1 `handle` handler2
handler2 e = stuff2 `handle` handler1

-- 
Fergus Henderson [EMAIL PROTECTED]  |  "I have always known that the pursuit
WWW: http://www.cs.mu.oz.au/~fjh  |  of excellence is a lethal habit"
PGP: finger [EMAIL PROTECTED]| -- the last words of T. S. Garp.





Re: Exceptions are too return values!

1998-06-16 Thread Fergus Henderson

On 15-Jun-1998, Peter White peter@galois wrote:
 
 On June 15, Fergus Henderson writes
 
  As noted earlier, things like heap overflow, and stack overflow 
  are different from other kinds of exceptions.  They can't be modelled
  using the domain-theoretic semantics.  Rather, they reflect the failure
  of the operational semantics to accurately reflect the domain-theoretic
  semantics.  Thus the treatment of these exceptions may need to be
  different to the treatment of ordinary exceptions.
 
 One of the advertisements of Haskell is that you can reason
 about your program, by performing mathematical proofs about
 the program. Haskell has gone a long way to incorporating IO
 and stateful computations in such a way that you still get
 referential transparency, and you can still reason about programs.
 If the operational semantics fails to reflect, the domain-theoretic
 semantics, then it would appear that the ability to reason about
 the programs dissappears.

This is not the case here.  The reason is that although the operational
semantics are not complete w.r.t. the denotational (domain-theoretic)
semantics, they are sound.  That is, you can't use the denotational semantics
to prove that your program won't get a heap overflow; but you can use them
to prove that if your program doesn't get a resource failure like that,
then it will compute the right answer.

If you want to reason about resource limits, then you need to use
an operational semantics, not the denotational semantics.

 I think it is a requirement upon a
 Haskell implementation to preserve the independence of threads
 by "localizing" the resources to the threads, such that each thread
 can predict by itself, independently of any other thread, whether
 its resources will be sufficient.

I don't think this is desirable in the general case.
I think it would be useful to *allow* threads to reserve
resources, but often it is difficult to predict in advance
exactly how much each thread will use, and frequently it
is better to deal with resource failures when they arise.

-- 
Fergus Henderson [EMAIL PROTECTED]  |  "I have always known that the pursuit
WWW: http://www.cs.mu.oz.au/~fjh  |  of excellence is a lethal habit"
PGP: finger [EMAIL PROTECTED]| -- the last words of T. S. Garp.





Re: Exceptions are too return values!

1998-06-16 Thread Fergus Henderson

On 15-Jun-1998, Fergus Henderson [EMAIL PROTECTED] wrote:
 On 12-Jun-1998, Scott Turner [EMAIL PROTECTED] wrote:
  At 14:40 1998-06-10 +0100, you wrote:
  
  Here's a reasonable design for exceptions in Haskell:
  
  * handle :: (String - IO a) - IO a - IO a
  
  You probably realized more quickly than I how this
  can leak exceptions.
 ...
  Is this considered a drawback?
 
 This kind of exception handling can "leak" exceptions, but not in the
 way you described.
...
  What I mean is
  
  main = do quotient - handle (const (return 0)) (return (0 / 0)
   -- Looks plausible
   -- but the exception isn't raised yet.
print quotient -- Here the expression 0/0 is evaluated
   -- and the exception is raised with no handler.
 
 This is not correct.  This example would print out `0' rather than raising
 an uncaught division by zero exception.

I'm afraid I must retract those statements.  Scott Turner was quite correct,
and I was mistaken.  My apologies!

As Scott pointed out to me in personal email, SLPJ's definition of `handle'

  | * handle :: (String - IO a) - IO a - IO a
  |   (handle h a) tries to perform the action a.
  |   If doing so delivers a set of exceptional values then
  |   apply the exception handler h to the string that names
  |   one of them.  It is not defined which of the exceptional
  |   values is picked.

means that it only catches exceptional values in the I/O action,
not exceptional values in the return value.

Regarding Scott's question

 Is this considered a drawback?

my answer is still much the same -- yes, it's a drawback,
but I'd place the blame more on laziness than exception handling.
I consider it only a minor drawback, since the "leakage" can be
avoided if you use a version of `handle' which is strict in the return
value, e.g.

strict_handle handler action = handle handler strict_action where
strict_action = do value - action
   seq value return value
   -- or with `hyper_seq' instead of `seq'

-- 
Fergus Henderson [EMAIL PROTECTED]  |  "I have always known that the pursuit
WWW: http://www.cs.mu.oz.au/~fjh  |  of excellence is a lethal habit"
PGP: finger [EMAIL PROTECTED]| -- the last words of T. S. Garp.





Re: Exceptions and functions. Second round?

1998-06-16 Thread Hans Aberg

At 14:01 +0200 98/06/16, Jerzy Karczmarczuk wrote:
There is - in my opinion - nothing "exceptional" in *standard* imperative
control structures. OK, I admit that I am a sinner myself, and I had
written some small event-driven programs using (ppardonnez le mot)
"longjump" in C, but I believe strongly that the functional programming
community with the monadic religion etc. is much more close to the Truth.

  I think you are raising the issue of exceptions without handling it
properly. :-)

  Of course, when leaping to the next level of abstraction, exceptions are
as exceptional as irrational numbers are irrational and the imaginary
complex unit is imaginary in the original linguistic semantic sense, that
is, not at all. And C is a language whose trademark is the absence of
logical structure described by theory, so what's done in that language is
rather misleading if one wants to produce a new generation of languages
admitting new abstractions for the convenience to people that can think in
terms of abstractions and by that do more efficient work.

  In fact, the opposite seems to happen, the new concept of exceptions
seems to fit those old imperative ad hoc structures into a nice single
abstraction.

  As we sit here with a language, Haskell, which normally does not admit
imperative structures, using exceptions might be a neat way to do it.

  Hans Aberg
  * Email: Hans Aberg mailto:[EMAIL PROTECTED]
  * Home Page: http://www.matematik.su.se/~haberg/
  * AMS member listing: http://www.ams.org/cml/






Re: Exceptions are more than just return values!

1998-06-16 Thread Hans Aberg

At 12:15 +0100 98/06/16, Tony Finch wrote:
I like the idea of the non-deterministic exception system that has
been proposed, but it'll be interesting to see how well it works in
real life...

  Perhaps one can have them both with handlers handle_absolutely and
handle_maybe, so that user can play around with them both and compare.

  Hans Aberg
  * Email: Hans Aberg mailto:[EMAIL PROTECTED]
  * Home Page: http://www.matematik.su.se/~haberg/
  * AMS member listing: http://www.ams.org/cml/






Re: Exceptions and functions. Second round?

1998-06-16 Thread Alastair Reid


[EMAIL PROTECTED] (Greg Michaelson) writes:
 In SML(sorry...), in: exp1 handle exp2
 exp1 is evaluated and any exception raised within it is handled by an
 appropriate handler in exp2. If there isn't one then the exception
 is handled in the enclosing environment for the whole construct. Similarly,
 if an exception is raised in exp2 then it is handled in the enclosing
 environment. So exception handling follows a stack based regime.
 
 Instead, how about having exp2 handle exceptions raised within itself 
 and also allowing mutually recursive handlers?

No need to wire this into the semantics/implementation - it's easy
to implement your "recursive catch" using the plain catch:

  rcatch :: IO a - (IOError - IO a) - IO a
  m `rcatch` h = m `catch` \err - (h err `catch` h)

but notice that I call plain catch when invoking the handler - so
we won't get into infinite loops.

If infinite loops are what you want :-), then we have "really recursive catch"

  rrcatch :: IO a - (IOError - IO a) - IO a
  m `rrcatch` h = m `catch` \err - (h err `rrcatch` h)

Yet another variant would be to invoke the handler up to 10 times (say)
before giving up and invoking the outer handler.

  This might form a very
 nice inter-process communication mechanism, which may be recognised
 by people who have written interrupt driven multi-process systems.

I sort of see how this might work - but I've only _read about_ such systems
- not actually implemented them.  Where could I find out more?


Alastair

ps I'm getting kinda worried about people talking about using the
   exception handling mechanism to implement various control constructs.
   While our non-deterministic semantics is (I hope) fine for writing
   robust programs, I can't see how to build __predictable__ control
   constructs on top of it and I have no desire to modify the implementation
   and semantics just so that you can do so.

   I also think we need to spend some time playing with the GHC-based 
   implementation before we'll really know how it performs.  Just how big
   a problem will it be if an optimiser transforms a program that would have
   raised an error into a program that enters an infinite loop and triggers
   a timeout?  In some applications, this won't be a problem but it could
   be a real problem in others.






Re: Exceptions and functions. Second round?

1998-06-16 Thread Greg Michaelson

In SML(sorry...), in: exp1 handle exp2
exp1 is evaluated and any exception raised within it is handled by an
appropriate handler in exp2. If there isn't one then the exception
is handled in the enclosing environment for the whole construct. Similarly,
if an exception is raised in exp2 then it is handled in the enclosing
environment. So exception handling follows a stack based regime.

Instead, how about having exp2 handle exceptions raised within itself 
and also allowing mutually recursive handlers? This might form a very
nice inter-process communication mechanism, which may be recognised
by people who have written interrupt driven multi-process systems. It
probably has horrendous semantic implications...

Greg Michaelson





Re: Exceptions are too return values!

1998-06-15 Thread Fergus Henderson

On 12-Jun-1998, Scott Turner [EMAIL PROTECTED] wrote:
 At 14:40 1998-06-10 +0100, you wrote:
 
 Here's a reasonable design for exceptions in Haskell:
 
 * handle :: (String - IO a) - IO a - IO a
 
 You probably realized more quickly than I how this
 can leak exceptions.
...
 Is this considered a drawback?

This kind of exception handling can "leak" exceptions, but not in the
way you described.  Yes, this is a drawback, but it's not nearly as big
a drawback it would be if exceptions could leak in the way you were
talking about.  Furthermore, the leakage seems to be inherent to lazy
evaluation, so I'd consider it a drawback of lazy evaluation rather than
a drawback of exception handling.  The user can avoid such leakage,
so long as they're willing to lose some laziness. 

Details below.

 What I mean is
 
 main = do quotient - handle (const (return 0)) (return (0 / 0)
  -- Looks plausible
  -- but the exception isn't raised yet.
   print quotient -- Here the expression 0/0 is evaluated
  -- and the exception is raised with no handler.

This is not correct.  This example would print out `0' rather than raising
an uncaught division by zero exception.

The reason is basically that the handler is established lazily too.
When `print' evaluates its argument, first the handler is
established, then 0/0 is evaluated, then the handler catches
the exception and returns 0.

This may not have been obvious from SLPJ's original description,
but if your consider the domain-theoretic semantics, it has to be
this way.  SLPJ's original description was as follows:

 | * handle :: (String - IO a) - IO a - IO a
 |   (handle h a) tries to perform the action a.
 |   If doing so delivers a set of exceptional values then
 |   apply the exception handler h to the string that names
 |   one of them.  It is not defined which of the exceptional
 |   values is picked.

The result of performing the action `return (0 / 0)'
is a (singleton) set of exceptional values, so the effect
of `handle (const (return 0)) (return (0 / 0))' must be
to apply `const (return 0)' to one of those values,
which in turn has the same effect as `return 0'.
The fact that this is all evaluated lazily doesn't change
the semantics.

If you want to understand the operational semantics in more detail,
then it may perhaps be clearer if you look at my implementation of his `handle'
using `ndset_handle' and `ndset_choose', since that breaks things up into
smaller pieces, seperating out the exception handling from the
nondeterministic choice.  But probably the simplest way of seeing it is
to look at the domain-theoretic semantics as outlined above.

So, your example is not a problem.  However, it is true that this kind
of exception handling does in a certain sense "leak" exceptions.  This
is because `handle' only catches exceptions that occur during the
evaluation of the top level of the value, it doesn't catch exceptions
that occur duing evaluation of the sub-components.
For instance, if we just modify your example slightly,
then we get an example where exceptions really do "leak" out:

main = do list - handle (const (return [])) (return [0 / 0])
  print list

This example will print "[" and then throw an uncaught division by zero
exception.

In order to avoid this, the user needs to force strict

main = do list - handle (const (return [])) (return e) `hyperseq` e
  where e = return [0 / 0]
  print list

Here `hyperseq' is a function that is like `seq' except
that it forces complete evaluation, not just evaluation to WHNF
(weak head normal form).

class HyperEval a where
hyperstrict :: (a - b) - a - b
hyperseq :: a - b - b
hyperstrict f x = x `hyperseq` f x

instance HyperEval a = HyperEval [a] where
[] `hyperseq` val = val
(x:xs) `hyperseq` val = x `hyperseq` (xs `hyperseq` val)

If we use a version of `handle' where the handler is the second argument
rather than the first (a good idea, IMHO!), then the example could be
written slighly more elegantly, using `hyperstrict' rather than `hyperseq',
as either

main = do list - hyperstrict handle (return [0/0]) (const (return []))
  print list

or if you prefer

main = do list - (return [0/0])
`hyperstrict handle` (const (return []))
  print list

P.S.  Is there any reason why something like `HyperEval'
isn't built in to Haskell, or at least include in the
Haskell Library report?  Is there any implementation-specific
precedent for something like this in say ghc?

-- 
Fergus Henderson [EMAIL PROTECTED]  |  "I have always known that the pursuit
WWW: http://www.cs.mu.oz.au/~fjh  |  of excellence is a lethal habit"
PGP: finger [EMAIL PROTECTED]| -- the last words of T. S. Garp.





Re: Exceptions are too return values!

1998-06-15 Thread Fergus Henderson

On 13-Jun-1998, Peter White peter@galois wrote:
 
 I wonder if there is another issue relating potential nondeterminism
 of exceptions to the independence of threads. It is supposed to be
 the case that two different threads have behavioral independence, so
 that an implementation could run the threads in any order, interleave
 their execution in any way, and the two threads would still give the
 same results.

Well, that depends on whether you want parallelism, or concurrency.
If you just want parallelism, i.e. you're just using threads to
improve performance, then yes, the order of interleaving should
not affect the results.  But if you're using concurrency, then this
isn't necessarily true -- the order of interleaving may affect the
results, and this may be exactly what you want.

 Take the case of a heap overflow exception.

As noted earlier, things like heap overflow, and stack overflow 
are different from other kinds of exceptions.  They can't be modelled
using the domain-theoretic semantics.  Rather, they reflect the failure
of the operational semantics to accurately reflect the domain-theoretic
semantics.  Thus the treatment of these exceptions may need to be
different to the treatment of ordinary exceptions.

In particular, instead of

data MaybeException a = OK a | GotException (NDSet Exception)
ndset_catch :: a - MaybeException a

you need something like

data ResourceFailure = StackOverFlow | HeapOverFlow | ...
data MaybeResourceFailure a = Computed (MaybeException a)
| Failed ResourceFailure
ndset_catch_all :: a - NDSet MaybeFailure

Timeouts may also be considered as resource failures.  Interrupt
handlers could also be considered as exceptions or resource failures,
but I think is probably nicer to consider them as forms of
concurrency.

 Suppose the two threads
 demand more memory than is provided in the computer. One of the two
 threads will hit a heap overflow exception. In order to have the
 implementation guarantee thread independence, the heap overflow of
 one thread cannot depend upon the memory consumption of the other
 thread. If there is a dependence, then one thread can determine the
 behaviour of the other thread by choosing to consume memory on the
 heap or not.

If you're worried about covert communication channels, then yes, you
have to worry about things like this.  But generally covert communication
channels are not an issue.  So in general it's enough to say that
whether or not you get a HeapOverflow resource failure is nondeterministic.

-- 
Fergus Henderson [EMAIL PROTECTED]  |  "I have always known that the pursuit
WWW: http://www.cs.mu.oz.au/~fjh  |  of excellence is a lethal habit"
PGP: finger [EMAIL PROTECTED]| -- the last words of T. S. Garp.





Re: Exceptions are too return values!

1998-06-15 Thread Alastair Reid


 On Mon, 15 Jun 1998, Fergus Henderson wrote:
 
  P.S.  Is there any reason why something like `HyperEval'
  isn't built in to Haskell, or at least include in the
  Haskell Library report?  Is there any implementation-specific
  precedent for something like this in say ghc?

Dave Tweed [EMAIL PROTECTED] added:
 I'd like to second this. It would have been very useful in some of the
 stuff I've written, particularly since (understandably enough) when using
 newtype you can't put ! annotations within the data-type.

I believe this is what the derive program (available from Glasgow's web site)
was originally developed for.


-- 
Alastair Reid  Yale Haskell Project Hacker
[EMAIL PROTECTED]  http://WWW.CS.Yale.EDU/homes/reid-alastair/






[Fwd: Re: Exceptions are too return values!]

1998-06-15 Thread Noel

--3E1737327A
Content-Type: text/plain; charset="us-ascii"

Alastair Reid wrote:

 I believe this is what the derive program (available from Glasgow's web site)
 was originally developed for.

Hi,
I'm the implementor of the software formerly known as 'Derive`, and
would just make a few points.

1. I've been threatened with legal action from Soft Warehouse Inc. for
infringing their trademark "DERIVE".  The full details are at 
http://www.dcs.gla.ac.uk/~nww/Derive/derivehome.html
In summary I'm not allowed to refer to my software using that name, and
must also inform others to do the same.

2. The software formerly known as 'Derive' was a little project written
during the first year of my PhD. Although it originates from Glasgow,
one should not assume it enjoys the same level of robustness or support
as other Glasgow FP tools.

3. Personally, I think that there is a need for a type-sensitive
preprocessor for Haskell.  Extending the derivable classes was the
motivating example, but there are other applications.  The software
formerly known as Derive is a first attempt at this.  I think it is time
for someone to develop this idea properly into a robust system. 
However, due to my PhD I don't have time for this.  

regards
noel.

-- 
Noel Winstanley
Dept of Computing Science
University of Glasgow
http://www.dcs.gla.ac.uk/~nww/   
mailto:[EMAIL PROTECTED]

--3E1737327A
Content-type: message/rfc822

Return-Path: [EMAIL PROTECTED]
Delivery-Date: Mon, 15 Jun 1998 14:58:59 +0100
Received: from dcs.gla.ac.uk 
  by vanuata.dcs.gla.ac.uk   
  id [EMAIL PROTECTED]; Mon, 15 Jun 1998 14:57:05 +0100
Old-Received: from easter.dcs.gla.ac.uk.dcs.gla.ac.uk (actually host easter)   
  by vanuata with SMTP DCS (MMTA) with ESMTP;  Mon, 15 Jun 1998
   
  14:56:57 +0100
Old-Received: by easter.dcs.gla.ac.uk.dcs.gla.ac.uk (8.8.5/Dumb)id OAA00405; 
  Mon, 15 Jun 1998 14:56:55 +0100
Old-Received: from haggis.cs.yale.edu (actually host HAGGIS.AI.CS.YALE.EDU)   
  by vanuata with SMTP (MMTA) with ESMTP;  Mon, 15 Jun 1998 
14:39:41   
  +0100
Old-Received: from haggis.cs.yale.edu (reid@localhost [127.0.0.1])  by 
  haggis.cs.yale.edu (8.8.7/8.8.7) with ESMTP  
   
  id JAA27815;  Mon, 15 Jun 1998 09:37:53 -0400
Message-Id: [EMAIL PROTECTED]
To: Dave Tweed [EMAIL PROTECTED]
cc: [EMAIL PROTECTED]
Subject: Re: Exceptions are too return values! 
In-reply-to: Your message of "Mon, 15 Jun 1998 10:03:18 BST." 
Pine.SGI.3.96.980615095746.2241B-10@neon 
Sender: [EMAIL PROTECTED]
Precedence: bulk   

8Qxd$QC/sdeK{93/{KA]T@gir{b8(rd5/zL85UcsTGty!z9Nx%Z+0e193YVEXFcWdM.]+uyVYA6 
WNNn]tdh-oQ]/#\R;Vts^}W]a%+%VqSEAu
Date: Mon, 15 Jun 1998 09:37:52 -0300
From: Alastair Reid [EMAIL PROTECTED]
Resent-Date:  Mon, 15 Jun 1998 14:57:05 +0100
Resent-From: [EMAIL PROTECTED]
Resent-To: [EMAIL PROTECTED]
MIME-Version: 1.0
Content-Type: text/plain; charset="us-ascii"





 On Mon, 15 Jun 1998, Fergus Henderson wrote:
 
  P.S.  Is there any reason why something like `HyperEval'
  isn't built in to Haskell, or at least include in the
  Haskell Library report?  Is there any implementation-specific
  precedent for something like this in say ghc?

Dave Tweed [EMAIL PROTECTED] added:
 I'd like to second this. It would have been very useful in some of the
 stuff I've written, particularly since (understandably enough) when using
 newtype you can't put ! annotations within the data-type.

I believe this is what the derive program (available from Glasgow's web site)
was originally developed for.


-- 
Alastair Reid  Yale Haskell Project Hacker
[EMAIL PROTECTED]  http://WWW.CS.Yale.EDU/homes/reid-alastair/



--3E1737327A--





Re: Exceptions are too return values!

1998-06-14 Thread Hans Aberg

  Here is an input on the exception handling question:

  In (pseudo) C++, one can write
try { ... }
catch (A) { if (C) then handle_it else rethrow }
But in a functional language it would be more reasonable to write
if (C) then catch(A) { handle_it }
or something like that, and let the compiler rewrite it to the C++
construction above (the latter which has the advantage that the handling
points are known in advance).

  Then this could be generalized: If f contains the handling of exceptions
E_1, ..., E_k, then f(x) rewrites to
catch (E_1, ..., E_k) { f(x), rethrow if not caught }
Then f(x) is only computed if needed because it handles the exception, but
it also ensures that the exception is handled if f has the capacity to do
so.

  I am not sure how this idea would work out in a functional language, but
this would be a part of the analysis one would have to do when implementing
exceptions.

  Hans Aberg
  * Email: Hans Aberg mailto:[EMAIL PROTECTED]
  * Home Page: http://www.matematik.su.se/~haberg/
  * AMS member listing: http://www.ams.org/cml/






Re: Exceptions are too return values!

1998-06-12 Thread Hans Aberg

At 10:50 +1000 98/06/12, Fergus Henderson wrote:
Infinities are probably best treated as a seperate issue.
That is, infinities should not correspond to exceptions.
If you have a type which supports infinities, then 1/0 should return
infinity, not raise an exception.  Conversely, if you want 1/0 to not
raise an exception, then your type should support infinities.

  I think it is best to let 1/0 throw an exception "divide-by-zero" -- then
this can be used to build types that support infinities (like projective
spaces).

  Hans Aberg
  * Email: Hans Aberg mailto:[EMAIL PROTECTED]
  * Home Page: http://www.matematik.su.se/~haberg/
  * AMS member listing: http://www.ams.org/cml/






Re: Exceptions are too return values!

1998-06-12 Thread Scott Turner

At 14:40 1998-06-10 +0100, you wrote:

Here's a reasonable design for exceptions in Haskell:

* handle :: (String - IO a) - IO a - IO a

You probably realized more quickly than I how this
can leak exceptions.  What I mean is

main = do quotient - handle (const (return 0)) (return (0 / 0)
 -- Looks plausible
 -- but the exception isn't raised yet.
  print quotient -- Here the expression 0/0 is evaluated
 -- and the exception is raised with no handler.

Is this considered a drawback?

--
Scott Turner
[EMAIL PROTECTED]   http://www.ma.ultranet.com/~pkturner





Re: Exceptions and return

1998-06-11 Thread Fergus Henderson

On 10-Jun-1998, Hans Aberg [EMAIL PROTECTED] wrote:
   I think that experts on implementing lazy languages can tell you about
 the problems of implementing C++ "zero-overhead" exceptions (though
 logically equivalent to an exception monad) into a lazy language like
 Haskell.

There's little point trying to implement C++-like so-called "zero-overhead"
exceptions in any language with garbage collection.  It would
probably result in a performance loss.

The "zero-overhead" refers to the time cost of setting up a handler.
Because C++ doesn't have garbage collection, any class that does
dynamic allocation needs a destructor, and for every local variable
with a destructor the implementation needs to set up a handler to
call that destructor when an exception is thrown.  Since classes
with destructors are so common, this needs to be very cheap.
C++ implementations are willing to pay a large space overhead,
plus a significant increase in implementation complexity, plus
an increase in the overhead of actually throwing an exception,
in order to reduce the cost of establishing a handler.
However, in languages with garbage collection, destructors or
finalizers are rare, so there's no need to go to that effort,
and even if you did, the increased space costs and resulting
decreased locality would probably make it not worthwhile.

-- 
Fergus Henderson [EMAIL PROTECTED]  |  "I have always known that the pursuit
WWW: http://www.cs.mu.oz.au/~fjh  |  of excellence is a lethal habit"
PGP: finger [EMAIL PROTECTED]| -- the last words of T. S. Garp.





Re: Exceptions and return

1998-06-11 Thread Fergus Henderson

On 10-Jun-1998, Hans Aberg [EMAIL PROTECTED] wrote:
 At 01:09 +1000 98/06/11, Fergus Henderson wrote:
 There's little point trying to implement C++-like so-called "zero-overhead"
 exceptions in any language with garbage collection.  It would
 probably result in a performance loss.
 
   This is good indeed.
 
   But I think the C++ exceptions have another advantage, namely that it
 stops further computations and skips directly forward to the first point
 where the exception is caught. Java, which has garbage collection, probably
 does the same as in C++, but when using the monadic approach in Haskell it
 does not work so: The code excepted propagates through a series of identity
 mappings in the exception monad, which is slow.

Well, there's basically three ways that I know of to implement exceptions,
other than the C++ "zero-overhead" style:

(a) have every function return an indicator saying whether it
  succeeded or threw an exception, and after each function
  call this indicator and if it is an exception, rethrow it

(b) use a special stack frame for exception handlers;
  ordinary returns incur no overhead, but throws
  need to scan the stack looking for handlers

(c) use a seperate stack for exception handlers;
  ordinary returns incur no overhead, and
  when an exception is thrown it need only
  look at the topmost entry on the exception handler stack.
  But having an extra stack complicates things,
  and may make threads more expensive, etc.

Clearly (a) is not very good.  You seem to be arguing for (c),
but I think that in practice the improvement from (b) to (c)
is not likely to be important for the vast majority of programs.
I suspect you would be happy with (b).

   So the real problem is if one can implement an exception monad in Haskell
 which does not propagate through the code (i.e. skips forward directly to
 the point where the exception is caught).

Yes, this ought to be possible -- indeed SLPJ alluded to doing that kind of
thing when he talked about improved I/O performance.  I think he was
talking about (b) rather than (c), though.

-- 
Fergus Henderson [EMAIL PROTECTED]  |  "I have always known that the pursuit
WWW: http://www.cs.mu.oz.au/~fjh  |  of excellence is a lethal habit"
PGP: finger [EMAIL PROTECTED]| -- the last words of T. S. Garp.





Re: Exceptions are too return values!

1998-06-10 Thread Dave Tweed

On Tue, 9 Jun 1998, Mariano Suarez Alvarez wrote:

 In a typed language, a function *cannot* be applied to something outside
 its domain. That's the whole point!

That represents a certain degree of idealisation though? E.g., sqrt _as a
(single valued) mathematical function_ has domain R^{=0}. Certainly I
could define a constructed datatype which is exactly this set. But if I
want to use machine floats the natural type is Float-Float. Type classes
don't appear to help because a condition for type (i.e., set) membership
like (=0) can't in general be decided at compile time. So I seem to be
faced with the fact that my argument type is a superset of the domain, and
I have to either check at run time or prove that only elements of the
domain will ever actually turn up.

Types catch lots of errors, but by no means all of them. (Presumably
similar examples can occur by, e.g., defining size balanced trees as Tr a
= Nd a (Tr a) (Tr a) | Lf which doesn't guarantee that a type-checking
expression is necessarily size-balanced.)

Or am I missing a terribly obvious point? 

cheers, dave

email: [EMAIL PROTECTED]   "Taught the wife some html. __Bad
www.cs.bris.ac.uk/~tweed/pi.htm   move__." -- Alan Cox
work tel: not available  





Re: Exceptions and return

1998-06-10 Thread Jerzy Karczmarczuk

Hans Aberg writes:

   I have noted that C++ exceptions (Exception(a), where a is any piece of
 data) can be used to implement dynamic versions of C++ constructs such as
 ``return'' and ``break'' (because I have done it).
 
   So exceptions are certainly more general than function returns, at least
 in this context.
 
   Hans Aberg


Now, I do not understand that. Certainly one may say that *all* imperative
constructs are more general than "ordinary" function returns (trivial
Monad...), and in particular with the 'C' longjump you may do horrible
things, but if the environment trapping is just used to implement "return",
then I believe that all that can be "functionalized" through continuations.

With -- quite functional -- call/cc in Scheme (or other mechanisms 
dealing with first class continuations) you may implement even more exotic 
control constructs, coroutines, asynchronous message dispatching, etc.
They are still functional, but they include the hidden state transformation.

I believe that Hans standpoint depends on his vision of the *state* of
the system.


**

Yours
Jerzy Karczmarczuk
University of Caen, France





Re: Exceptions and return

1998-06-10 Thread Hans Aberg

At 01:09 +1000 98/06/11, Fergus Henderson wrote:
There's little point trying to implement C++-like so-called "zero-overhead"
exceptions in any language with garbage collection.  It would
probably result in a performance loss.

  This is good indeed.

  But I think the C++ exceptions have another advantage, namely that it
stops further computations and skips directly forward to the first point
where the exception is caught. Java, which has garbage collection, probably
does the same as in C++, but when using the monadic approach in Haskell it
does not work so: The code excepted propagates through a series of identity
mappings in the exception monad, which is slow.

  So the real problem is if one can implement an exception monad in Haskell
which does not propagate through the code (i.e. skips forward directly to
the point where the exception is caught).

  Hans Aberg
  * Email: Hans Aberg mailto:[EMAIL PROTECTED]
  * Home Page: http://www.matematik.su.se/~haberg/
  * AMS member listing: http://www.ams.org/cml/






RE: Exceptions are too return values!

1998-06-10 Thread Karlsson Kent - keka

It's nice to have SOME way of handling exceptions, but...

 The implementation does not keep sets of exceptional values,
 of course.  It simply propagates the first one it trips
 over to the nearest enclosing handler.

One argument that can be made in favour of a generalised more IEEE-like
mechanism is that it is usually such a pain to handle an exception that
propagates like this that one most often does not bother to handle it
properly (i.e. try to continue with the task, which is usually the best
thing to do; user hitting 'break' or 'esc' excepted, but those are not
'exceptions' in this sense).  And in many cases, using some reasonable
'continuation value' (which have already been specified and widely
implemented for f.p. arithmetic) and a set of notes on exceptions that
have occurred, is sufficient and gives a nicer behaviour of the program.

Say that the application is to produce a simple function curve, for a
function given as argument, so only the type is known and no other
properties.  Say that it does this by computing a list of pairs later to
be turned into a nice-looking graph.  Say also that overflows occur, or
out-of-domain-errors occur.  Having these errors propagate up to an IO
monad or similar for handling, then having to restart, in the handler,
the graph calculation at the appropriate place is much more difficult to
handle (and is likely not to be done, or to be done in a buggy way) than
just plodding on as if (nearly) nothing out of the ordinary happened.  I
don't think that this situation is so exotic that one can safely ignore
it.  Indeed this behaviour has been specified as the default behaviour
for IEEE f.p.  And it is usually better to let the application continue
as normal, as long as no very critical error has occurred.  (Note that
not even divide-by-zero is considered critical in the IEEE world. It
does not even return a NaN, unless the numerator is also zero (or a
NaN).)

What one would need to do to obtain this, not that I'm suggesting it
very strongly, would be to generalise the IEEE model of exceptions from
f.p. arithmetic to values in general, including adding
Not-a-Proper-Value (NaPV) values to each non-f.p. datatype.  

A value of Haskell type T can be
 one of the values we know and love 
   (bottom, or constructor, or function,
depending on T),
   or NaPV (except for f.p. datatypes
which already have NaN values)

AND, implicitly,  it has a set of exception values
(this set is bottom if the value part is bottom).

Strict operations would propagate exceptions and NaPV values.
Certain predefined functions would be allowed to "read", or "replace"
the exception set part, something like:

add_exceptions :: a - Exceptions - a

where the Exceptions would be built into the result, and

read_and_clear_exceptions :: a - (a - Exceptions - b) - b

where the function argument would be given the value with cleared
Exceptions part, and as a second argument, the given Exceptions part.
And all is purely functional... (Unless I missed something.)

Yes, I have been ignoring performance issues.  Generating and keeping
Exceptions values around everywhere can be very taxing.  It would be
helpful to have an easy way of saying that the Exceptions part need not
be built-into the value (effectively clearing it, though the proper
Exceptions are propagated), changing the underlying datatype and
delaying the building-in.  It still may not be easy to get this very
efficient.  Indeed in the imperative (and IEEE arithmetic)world it is
never built-in, but one has one exceptions value per thread 'on the
side' (limited to arithmetic exceptions). (One such value per process is
not sufficient these days when multi-threaded processes are used.)

/kent k





Re: Exceptions are too return values!

1998-06-09 Thread Mariano Suarez Alvarez

On Mon, 8 Jun 1998, S. Alexander Jacobson wrote:

 1. it is not logically consistent to treat exceptions as return values

A function cannot do anything but return a value, can it? 

 For example, suppose that we define a new function:
 
  foo' a b = a + b -- foo' is strict in its arguments
 
 Our intuition is that foo' is commutative.  foo' a b = foo' b a.
 But that turns out not to be true when you have exceptions.

That's the problem with intuitions: they can be wrong...  
Anyhow, if one is to have exceptions procteting +, I don't think that
commutativity of foo' is reasonable: to handle exceptions, you have to do
checks, and that you can only do in one order or another. 

 Take x and y from before,
 
  z = foo' x' y'
 
 What is the value of z? Haskell does not promise to evaluate arguments in
 any particular order so, depending on implementation, z may be either
 Exception DivideByZero or Exception NotFactorialDomain -1.  

Actually, using a monad to manage exceptions you can (maybe, have to) 
choose a definite order of evaluation of non-exceptionality-conditions. 

 Truly exceptional conditions are those that truly are outside of the
 domain of the function being evaluated. e.g. factorial -1
 The VALUE of (factorial -1) is not an exception.  Neither is the value of
 (factorial (1 `div` 0)).
 When a function is passed bad arguments, it is not meaningful (from a
 functional perspective) to have it return a value.

In a typed language, a function *cannot* be applied to something outside
its domain. That's the whole point!

 The value of a function over arguments outside its domain is undefined.
 When such an event occurs, the logically consistent behavior is to exit
 function evaluation and tell the caller what was wrong with the
 arguments passed (to the extent it is possible to do).

One can rightfully argue that, if one is willing to consider bottom (which
is a value we cannot test for!) a return value, which we are, considering
an exception a return value is *very* consistent. 
 
-- m

---
Mariano Suarez Alvarez  The introduction of
Departamento de Matematica   numbers as coordinates
Universidad Nacional de Rosario [...] is an act of violence
Pellegrini 250  A. Weyl
2000 Rosario - Argentina
e-mail: [EMAIL PROTECTED]
---





Re: Exceptions are too return values!

1998-06-09 Thread Alex Ferguson


Alex Jacobson:
 Ooops, I forgot to remove the "and".  Anyway, my point is that 
 1. it is not logically consistent to treat exceptions as return values
 2. as an implementation matter it violates laziness to do so

OK, now I follow.  And diagree. ;-)  On your second point first:
I'm not sure what you mean by "violates laziness"; it would be true
to say that adding exceptional return values in a given way might
well reduce the laziness of the program; but this can always be
obviated, given sufficient care.


  Using error-monad syntax might be a bit more palatable, but amounts to
  essentially the same thing.  Alternatively, you can define HOFs to
  "lift" an n-ary function to an exception-propagating equivalent:

 That is what I did with my Exception version 2 syntax.
 The problem is that doing this lifting ends up being non-lazy.

You're right, it alters the strictness of the program.  But one can
recover the original behaviour by delaying/eliminating the pattern-match,
though I again I agree this is a pain.


 You could argue that this problem is an artifact of the Haskell syntax and
 that we could add Exceptions to the Thunk to achieve the desired result
 (treating exceptions as return values).

I don't think I would, though!  (If I understand what you mean by this.)
The "problem" is an artifact of wanting to keep the language referentially
transparent, which a built-in throw/catch scheme of the sort you
suggest would scupper.


 Our intuition is that foo' is commutative.  foo' a b = foo' b a.
 But that turns out not to be true when you have exceptions.

That's true.  And it remains true _however_ one treats exceptions.
There's no way around that in general, I'm afraid, and I'll cite you
assorted papers on Observable Sequentiality if you really want the
grubby details.


 But the real point here is that Exceptions are, by definition, results
 that are outside the domain of the function being evaluated.  Treating
 exceptions as algebraic types may be comforting, but what you are really
 doing in that case is extending the domain of your function

Effectively, yes.  From a domain theory PoV, this is all that one could
possibly ever do, in fact ('error' included).


 -- and there are limits to how far you can go with that.

These being?


 Truly exceptional conditions are those that truly are outside of the
 domain of the function being evaluated. e.g. factorial -1
 The VALUE of (factorial -1) is not an exception.  Neither is the value of
 (factorial (1 `div` 0)).
 When a function is passed bad arguments, it is not meaningful (from a
 functional perspective) to have it return a value.
 The value of a function over arguments outside its domain is undefined.
 When such an event occurs, the logically consistent behavior is to exit
 function evaluation and tell the caller what was wrong with the
 arguments passed (to the extent it is possible to do).

I don't find this argument at all compelling.  If a value is "truly
outside the domain of the function being evaluated", then don't pass
it to it!  This may seem glib, but I do believe that its better SE
practice in general.  If there are exceptional conditions in "the world",
or if determining a sufficient precondition is not practicable, then I
repeat my advice concerning exceptional return values, a necessary evil
though they might be.


 Right now that means using the error function.  I am just saying that
 error isn't really enough for a production quality language.

Agreed.

 Does this make more sense?

It makes perfect sense, but I think that having exceptions as a language
mechanism in Haskell is not realistic or viable, for the reasons I
outlined before.  I don't pretend that the alternatives are trivial,
or even necessarily very pleasant-looking -- just that they're necessary.

Slainte,
Alex.