Re: [Haskell-cafe] Re: Exception handling in numeric computations

2009-03-31 Thread John Lato
On Mon, Mar 30, 2009 at 11:03 PM, Henning Thielemann
 wrote:
>
> On Sun, 29 Mar 2009, John Lato wrote:
>
>> On Sat, Mar 28, 2009 at 9:49 PM, Henning Thielemann
>>  wrote:
>>>
>>> On Sat, 28 Mar 2009, John Lato wrote:
>>>
 Honestly, me neither, until recently.  I'm only barely starting to
 understand it, and I do think there's a great deal of overlap.  Even
 if an error is a bug that can be fixed by the programmer, certain
 exceptional situations can also be fixed by the programmer by handling
 the exception, even if they can't be detected in advance.
>>>
>>> For example?
>>
>> A file not being written because of a permissions error.  This can't
>> be detected in advance due to effects from other processes, but it's a
>> predictable enough exception that the programmer should handle it for
>> IO.
>
> Indeed. However I still do not see the overlap of errors and exceptions. :-(

Really?  You wrote in a prior email:
>>> Btw. not handling an exception is an error.

An exception thrown at run-time reveals a programming error, and if
the exception could not be thrown in this context then the error
wouldn't exist either.  The error is that the programmer did not deal
with an exception.

Conceptually I think the difference between errors and exceptions is
clear, but many programming errors are a result of a lack or improper
handling of exceptions.  That's the overlap to which I refer.

>  Handling of exceptions may mean that you print a message and abort the
> affected operation, that is you often do not need a specific exception
> handling. E.g. if the user wants to load a file into an editor, and the file
> is read-protected, then the editor reports, that the file cannot be loaded
> and does not load it. The editor should keep running, in contrast to when it
> detects a programming error. The same should happen when the editor
> encounters a memory overflow. So I cannot follow the argument of "memory
> exhaustion shouldn't happen anymore today, so there is no need to handle
> it". I remember this was claimed in this thread, too. However, recovering
> from a memory exhaustion can be tricky. Can the garbage collector still free
> memory, when it cannot allocate memory temporarily?

I thought the argument was that "when memory exhaustion occurs in a
Haskell application, it is (usually) the result of a programming
error."  This means handling the exception and trying to continue work
is not the proper approach to dealing with memory exhaustion.

>>> Btw. not handling an exception is an error.
>>
>> Agreed generally.  But some exceptions are likely in given contexts,
>> others are not.  I don't think it's necessary to handle every possible
>> exception, just the ones that are likely and predictable for a given
>> activity.
>
> Since handling of exceptions often consist of reporting the exception and
> aborting an operation, it should always be managable to handle all possible
> exceptions.

Manageable, but possibly not useful for all functions.  I don't
believe that anyone's advocating that all IO functions are wrapped in
a 'try' or 'bracket', so long as there are exception handlers at
appropriate levels.

John
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: Exception handling in numeric computations

2009-03-30 Thread Henning Thielemann


On Sun, 29 Mar 2009, John Lato wrote:


On Sat, Mar 28, 2009 at 9:49 PM, Henning Thielemann
 wrote:


On Sat, 28 Mar 2009, John Lato wrote:


Honestly, me neither, until recently.  I'm only barely starting to
understand it, and I do think there's a great deal of overlap.  Even
if an error is a bug that can be fixed by the programmer, certain
exceptional situations can also be fixed by the programmer by handling
the exception, even if they can't be detected in advance.


For example?


A file not being written because of a permissions error.  This can't
be detected in advance due to effects from other processes, but it's a
predictable enough exception that the programmer should handle it for
IO.


Indeed. However I still do not see the overlap of errors and exceptions. 
:-(
 Handling of exceptions may mean that you print a message and abort the 
affected operation, that is you often do not need a specific exception 
handling. E.g. if the user wants to load a file into an editor, and the 
file is read-protected, then the editor reports, that the file cannot be 
loaded and does not load it. The editor should keep running, in contrast 
to when it detects a programming error. The same should happen when the 
editor encounters a memory overflow. So I cannot follow the argument of 
"memory exhaustion shouldn't happen anymore today, so there is no need to 
handle it". I remember this was claimed in this thread, too. However, 
recovering from a memory exhaustion can be tricky. Can the garbage 
collector still free memory, when it cannot allocate memory temporarily?



Btw. not handling an exception is an error.


Agreed generally.  But some exceptions are likely in given contexts,
others are not.  I don't think it's necessary to handle every possible
exception, just the ones that are likely and predictable for a given
activity.


Since handling of exceptions often consist of reporting the exception and 
aborting an operation, it should always be managable to handle all 
possible exceptions.


 Excluding generic "The impossible happened, file a bug report" 
handlers.


This is the one special case, where program errors are catched in order to 
allow debugging.___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: Exception handling in numeric computations

2009-03-30 Thread Henning Thielemann


On Mon, 30 Mar 2009, Simon Marlow wrote:


Nicolas Pouillard wrote:


By reading the documentation of 'hGetLine' [1] one can see that this 
function

can throw only an EOF exception so why not give it a type like below?

 hGetLine :: Handle -> ErrorT EOF IO String

Since one will have to handle the error case it would be better to 
treat only the possible cases, no?


I'm afraid the documentation is incomplete.  hGetLine can also fail because 
e.g. the device it was reading from has been unplugged, or it was reading 
from a network filesystem and the network has gone down.  And there might be 
yet more errors to be invented in the future, so I'm not sure it would be a 
good idea to reflect this level of detail in the type.


 Or the file could get read-protected. In principle I like to show the 
possible exceptions by types, but the point Simon raises is also 
important. I think IOError is good here and one must use the IOError 
analysis functions, to find out whether one can do something more specific 
in the case. For the default case there should be good possibilities to 
report the exception, e.g. translate it to the user language. For example 
when a file was not found, one can tell the user how to obtain it. But if 
the file is read-protected, a default message would suffice.
 The type IOError would still exclude an exception like "Parser failure". 
Thus explicit IOError is more descriptive than the implicit exceptions in 
IO monad today. It's still interesting how to handle sets of exceptions. 
If you use the exception type (Either ParserException IOError) then this 
is different from (Either IOError ParserException). I think we should use 
type classes for exceptions. Then you can use one type containing all 
exceptions in an application, but the type signature tells which 
exceptions are actually possible. E.g.


parser :: ParserException e => ExceptionalT e ParserMonad a

getLine :: IOException e => ExceptionalT e IO String

fileParser :: (ParserException e, IOException e) => ExceptionalT e IO String
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: Exception handling in numeric computations

2009-03-30 Thread Jonathan Cast
On Sat, 2009-03-28 at 01:27 +0100, Henning Thielemann wrote:
> Jonathan Cast schrieb:
> 
> >> i.e., that application's
> >> file decoding result should be an Either type that anticipates that
> >> the file encoding may be invalid.
> > 
> > This is pretty standard, I thought.  Do people write Haskell file input
> > methods that are undefined (`throw exceptions') on invalid inputs (e.g.,
> > do people use read to parse input from users or the file system[1])?
> 
> With
> 
>   case reads str of
>  [(x, "")] -> Just x
>  _ -> Nothing
> 
> you are safe. (I think it's now available as maybeRead.)

Hmm, hoogle doesn't know that name.

> In general, relying on a well-formed input file is an error. However, if
> your program detects a format error in file input, it could throw an
> exception. But this means that your program must be prepared for these
> problems.

Right.

> >> I will also guess if the file is unreadable because of an external
> >> I/O problem like no read access to file or filesystem, you would
> >> similarly expect this to be treated like that - I mean, ideally, e.g.,
> >> hGetLine :: Handle -> IO (Either IOError String)
> > 
> > IO is an exception monad already.  I don't think there's an objection to
> > throwing exceptions with throwIO and catching them in IO; my objection,
> > at least, is to designing your program to throw exceptions from
> > (ostensibly...) *pure* code and catch those in IO, in a live
> > environment.
> 
> Actually, I really object to have exception handling built into IO
> monad. Especially with extensible-exceptions package you can hide which
> kinds of exceptions can occur in a piece of code, which is a bad thing.
> When it comes to lazy I/O, which is problematic in itself, it is better
> to have explicit exceptions (i.e. IO (Either IOError String)) on top of
> exception-free IO. See the recent thread on safe lazy I/O:
>http://www.haskell.org/pipermail/haskell-cafe/2009-March/058205.html

Yi's new parsing library (just finished the paper a couple days ago)
seems quite appropriate to a lazy IO library; for that library, partial
grammars are errors anyway, so the issue doesn't really arise.

If you want IO failure/parsing failure handling in lazy IO, my
preference would be for a separate failure-handling hook (which can
throw an asynchronous exception if needed) rather than for any kind of
synchronous exception mechanism per se.  There's really not much you can
do, except tell the user either `hey, that doesn't look like valid
input!' or `sorry, the other side of the network connection
disappeared', and hope the operator can correct the issue.  I don't
think it's really important to let the input processing (as opposed to
parsing) code handle the situation specifically.

jcc


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


Re: [Haskell-cafe] Re: Exception handling in numeric computations

2009-03-30 Thread Jonathan Cast
On Fri, 2009-03-27 at 21:16 -0700, Donn Cave wrote:
> Quoth Henning Thielemann ,
> > On Fri, 27 Mar 2009, Donn Cave wrote:
> >
> >> Quoth Jonathan Cast ,
> >>
> >>> An `error' is any condition where the correct response is for the
> >>> programmer to change the source code :)
> >>
> >> That's a broad category, that overlaps with conditions where there
> >> are one or more correct responses for the original program as well.
> >>
> >> If I throw exceptions within the type system, using IO or whatever,
> >> and at some later time observe that I have caught one that would
> >> have been better handled closer to its source, for example.  I've
> >> already technically satisfied my requirement, since everything is
> >> in an exception monad, but the exception is still a bug.
> >
> > I don't understand this one.
> 
> A lame attempt to demonstrate that "condition where [a] correct
> response is to change the code"

Please don't mis-quote me.  I said `the' correct response.  Both
programming and operating computers are goal-directed processes; an
error is a situation where the program detects a bug such that it cannot
make progress toward the current goal without the programmer going and
fixing that bug.

If you have a condition where there is something (useful...) you want to
do within the context of the current source code, do not use an error to
signal that condition.  Use an exception.

> applies to too many cases to be
> useful.  (And that there are no cases where [the only] correct
> response is to change the code.)

I think Henning's response, and others, have adequately covered this.

jcc


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


[Haskell-cafe] Re: Exception handling in numeric computations

2009-03-30 Thread Simon Marlow

Nicolas Pouillard wrote:

Excerpts from Henning Thielemann's message of Sat Mar 28 21:49:33 +0100 2009:

On Sat, 28 Mar 2009, John Lato wrote:


From: Donn Cave 

I have never felt that I really understood that one.

Honestly, me neither, until recently.  I'm only barely starting to
understand it, and I do think there's a great deal of overlap.  Even
if an error is a bug that can be fixed by the programmer, certain
exceptional situations can also be fixed by the programmer by handling
the exception, even if they can't be detected in advance.

For example?

Btw. not handling an exception is an error.


I will also guess if the file is unreadable because of an external
I/O problem like no read access to file or filesystem, you would
similarly expect this to be treated like that - I mean, ideally, e.g.,
hGetLine :: Handle -> IO (Either IOError String)

Not necessarily, but possibly.  The big difference, of course, is that
decoding can be a pure operation, while reading never is.

I personally wouldn't mind if hGetLine had the type you give.  The way
I see it, there are two advantages to exceptions in this case.  The
first is that it's very easy for exceptions to trickle up and be
handled at a higher level.  The second 'advantage' is that the
programmer doesn't need to explicitly handle exceptions, whereas an
Either would require at least a pattern match to use the resulting
value.
  I'm afraid there is some confusion about what we mean with "exception". 
Do you only mean the thing that is silently handled in the IO monad? Is 
Left in Either an exception for you, too? In explicit-exception I call the 
corresponding constructor Exception, because that's what it is used for.
  I like to call all those things exceptions, because they are intended for 
the same purpose: Signalling exceptional situations that we cannot avoid 
in advance but that must be handled when they occur. You can use IO and 
its exceptions, I call them IO exceptions. It does not show in its types 
that and which exceptions can occur. Some people consider this an 
advantage, I consider this an disadvantage. You can use error codes or 
Either or even better Exceptional from the explicit-exception package, and 
Haskell is strong enough to treat these like exceptions in 
C++/Java/Modula-3 etc. because you can use their monad transformer 
variants ErrorT and ExceptionalT respectively. Those monad transformers 
allow automatical termination of a series of actions once an exceptional 
result is obtained. But since ErrorT and ExceptionalT are burned into the 
types, you cannot miss to handle them.

  So the most convenient type for hGetLine would be
hGetLine :: Handle -> ErrorT IOError IO String


By reading the documentation of 'hGetLine' [1] one can see that this function
can throw only an EOF exception so why not give it a type like below?

 hGetLine :: Handle -> ErrorT EOF IO String

Since one will have to handle the error case it would be better to treat only
the possible cases, no?


I'm afraid the documentation is incomplete.  hGetLine can also fail because 
e.g. the device it was reading from has been unplugged, or it was reading 
from a network filesystem and the network has gone down.  And there might 
be yet more errors to be invented in the future, so I'm not sure it would 
be a good idea to reflect this level of detail in the type.


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


[Haskell-cafe] Re: Exception handling in numeric computations

2009-03-29 Thread Achim Schneider
Henning Thielemann  wrote:

> Actually, I really object to have exception handling built into IO
> monad.
>
I couldn't agree more. If I want to write non-recovering code, I can
always just say

(Right foo) <- readLine

, and hope that the RTS is smart enough to print the error message in
the left constructor should that match fail.

-- 
(c) this sig last receiving data processing entity. Inspect headers
for copyright history. All rights reserved. Copying, hiring, renting,
performance and/or quoting of this signature prohibited.


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


Re: [Haskell-cafe] Re: Exception handling in numeric computations

2009-03-29 Thread Jonathan Cast
On Sat, 2009-03-28 at 12:51 +0300, Gregory Petrosyan wrote:
> On Sat, Mar 28, 2009 at 10:53 AM, Ketil Malde  wrote:
> > So the difference between an exception or an error type is mainly what
> > you intend to do about it.  There's no point in wrapping divisions in
> > Maybe unless you actually are able to do something useful to recover
> > from a zero denominator.
> 
> That is exactly the point I was trying to make.
> 
> When I write a code, I can't say in advance, in what way it will be used.
> So, for dealing with errors, I have to choose one way or another, mostly
> without that knowledge. When I'm using e.g. C++, it's easy:
> something like mantra "when in doubt, throw an exception" :-)
> combined with RAII, works good (but not ideal, of course).
> 
> So, I'll ask again: when I program in Haskell, what mechanism should I use?

If you don't know, use a (true) exception.  That is, Left or Exception
or throwIO.

Only use error or throw when you *know* the condition is un-recoverable.

jcc


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


Re: [Haskell-cafe] Re: Exception handling in numeric computations

2009-03-29 Thread John Lato
On Sat, Mar 28, 2009 at 9:49 PM, Henning Thielemann
 wrote:
>
> On Sat, 28 Mar 2009, John Lato wrote:
>
>>> From: Donn Cave 
>>>
>>> I have never felt that I really understood that one.
>>
>> Honestly, me neither, until recently.  I'm only barely starting to
>> understand it, and I do think there's a great deal of overlap.  Even
>> if an error is a bug that can be fixed by the programmer, certain
>> exceptional situations can also be fixed by the programmer by handling
>> the exception, even if they can't be detected in advance.
>
> For example?

A file not being written because of a permissions error.  This can't
be detected in advance due to effects from other processes, but it's a
predictable enough exception that the programmer should handle it for
IO.  Handling a DivByZero exception when doing IO, however, is very
likely wrong.

>
> Btw. not handling an exception is an error.

Agreed generally.  But some exceptions are likely in given contexts,
others are not.  I don't think it's necessary to handle every possible
exception, just the ones that are likely and predictable for a given
activity.  Excluding generic "The impossible happened, file a bug
report" handlers.

>
>>> I will also guess if the file is unreadable because of an external
>>> I/O problem like no read access to file or filesystem, you would
>>> similarly expect this to be treated like that - I mean, ideally, e.g.,
>>> hGetLine :: Handle -> IO (Either IOError String)
>>
>> Not necessarily, but possibly.  The big difference, of course, is that
>> decoding can be a pure operation, while reading never is.
>>
>> I personally wouldn't mind if hGetLine had the type you give.  The way
>> I see it, there are two advantages to exceptions in this case.  The
>> first is that it's very easy for exceptions to trickle up and be
>> handled at a higher level.  The second 'advantage' is that the
>> programmer doesn't need to explicitly handle exceptions, whereas an
>> Either would require at least a pattern match to use the resulting
>> value.
>
>  I'm afraid there is some confusion about what we mean with "exception". Do
> you only mean the thing that is silently handled in the IO monad?

Yes.  I was comparing exceptions as they exist in IO in Haskell to the
proposed hGetLine type.

> Is Left in
> Either an exception for you, too?

No.

> In explicit-exception I call the
> corresponding constructor Exception, because that's what it is used for.
>  I like to call all those things exceptions, because they are intended for
> the same purpose: Signalling exceptional situations that we cannot avoid in
> advance but that must be handled when they occur. You can use IO and its
> exceptions, I call them IO exceptions. It does not show in its types that
> and which exceptions can occur. Some people consider this an advantage, I
> consider this an disadvantage.

I remain undecided on this for the moment.  I should take another look
at explicit-exception now that I understand its intent better.

John
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: Exception handling in numeric computations

2009-03-29 Thread Nicolas Pouillard
Excerpts from Henning Thielemann's message of Sat Mar 28 21:49:33 +0100 2009:
> 
> On Sat, 28 Mar 2009, John Lato wrote:
> 
> >> From: Donn Cave 
> >>
> >> I have never felt that I really understood that one.
> >
> > Honestly, me neither, until recently.  I'm only barely starting to
> > understand it, and I do think there's a great deal of overlap.  Even
> > if an error is a bug that can be fixed by the programmer, certain
> > exceptional situations can also be fixed by the programmer by handling
> > the exception, even if they can't be detected in advance.
> 
> For example?
> 
> Btw. not handling an exception is an error.
> 
> >> I will also guess if the file is unreadable because of an external
> >> I/O problem like no read access to file or filesystem, you would
> >> similarly expect this to be treated like that - I mean, ideally, e.g.,
> >> hGetLine :: Handle -> IO (Either IOError String)
> >
> > Not necessarily, but possibly.  The big difference, of course, is that
> > decoding can be a pure operation, while reading never is.
> >
> > I personally wouldn't mind if hGetLine had the type you give.  The way
> > I see it, there are two advantages to exceptions in this case.  The
> > first is that it's very easy for exceptions to trickle up and be
> > handled at a higher level.  The second 'advantage' is that the
> > programmer doesn't need to explicitly handle exceptions, whereas an
> > Either would require at least a pattern match to use the resulting
> > value.
> 
>   I'm afraid there is some confusion about what we mean with "exception". 
> Do you only mean the thing that is silently handled in the IO monad? Is 
> Left in Either an exception for you, too? In explicit-exception I call the 
> corresponding constructor Exception, because that's what it is used for.
>   I like to call all those things exceptions, because they are intended for 
> the same purpose: Signalling exceptional situations that we cannot avoid 
> in advance but that must be handled when they occur. You can use IO and 
> its exceptions, I call them IO exceptions. It does not show in its types 
> that and which exceptions can occur. Some people consider this an 
> advantage, I consider this an disadvantage. You can use error codes or 
> Either or even better Exceptional from the explicit-exception package, and 
> Haskell is strong enough to treat these like exceptions in 
> C++/Java/Modula-3 etc. because you can use their monad transformer 
> variants ErrorT and ExceptionalT respectively. Those monad transformers 
> allow automatical termination of a series of actions once an exceptional 
> result is obtained. But since ErrorT and ExceptionalT are burned into the 
> types, you cannot miss to handle them.
>   So the most convenient type for hGetLine would be
> hGetLine :: Handle -> ErrorT IOError IO String

By reading the documentation of 'hGetLine' [1] one can see that this function
can throw only an EOF exception so why not give it a type like below?

 hGetLine :: Handle -> ErrorT EOF IO String

Since one will have to handle the error case it would be better to treat only
the possible cases, no?

[1]: 
http://www.haskell.org/ghc/docs/latest/html/libraries/base/System-IO.html#v%3AhGetLine

-- 
Nicolas Pouillard
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: Exception handling in numeric computations

2009-03-28 Thread Henning Thielemann


On Sat, 28 Mar 2009, John Lato wrote:


From: Donn Cave 

I have never felt that I really understood that one.


Honestly, me neither, until recently.  I'm only barely starting to
understand it, and I do think there's a great deal of overlap.  Even
if an error is a bug that can be fixed by the programmer, certain
exceptional situations can also be fixed by the programmer by handling
the exception, even if they can't be detected in advance.


For example?

Btw. not handling an exception is an error.


I will also guess if the file is unreadable because of an external
I/O problem like no read access to file or filesystem, you would
similarly expect this to be treated like that - I mean, ideally, e.g.,
hGetLine :: Handle -> IO (Either IOError String)


Not necessarily, but possibly.  The big difference, of course, is that
decoding can be a pure operation, while reading never is.

I personally wouldn't mind if hGetLine had the type you give.  The way
I see it, there are two advantages to exceptions in this case.  The
first is that it's very easy for exceptions to trickle up and be
handled at a higher level.  The second 'advantage' is that the
programmer doesn't need to explicitly handle exceptions, whereas an
Either would require at least a pattern match to use the resulting
value.


 I'm afraid there is some confusion about what we mean with "exception". 
Do you only mean the thing that is silently handled in the IO monad? Is 
Left in Either an exception for you, too? In explicit-exception I call the 
corresponding constructor Exception, because that's what it is used for.
 I like to call all those things exceptions, because they are intended for 
the same purpose: Signalling exceptional situations that we cannot avoid 
in advance but that must be handled when they occur. You can use IO and 
its exceptions, I call them IO exceptions. It does not show in its types 
that and which exceptions can occur. Some people consider this an 
advantage, I consider this an disadvantage. You can use error codes or 
Either or even better Exceptional from the explicit-exception package, and 
Haskell is strong enough to treat these like exceptions in 
C++/Java/Modula-3 etc. because you can use their monad transformer 
variants ErrorT and ExceptionalT respectively. Those monad transformers 
allow automatical termination of a series of actions once an exceptional 
result is obtained. But since ErrorT and ExceptionalT are burned into the 
types, you cannot miss to handle them.

 So the most convenient type for hGetLine would be
   hGetLine :: Handle -> ErrorT IOError IO String
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: Exception handling in numeric computations

2009-03-28 Thread Henning Thielemann


On Sat, 28 Mar 2009, Gregory Petrosyan wrote:


On Sat, Mar 28, 2009 at 10:53 AM, Ketil Malde  wrote:

So the difference between an exception or an error type is mainly what
you intend to do about it.  There's no point in wrapping divisions in
Maybe unless you actually are able to do something useful to recover
from a zero denominator.


That is exactly the point I was trying to make.

When I write a code, I can't say in advance, in what way it will be used.
So, for dealing with errors, I have to choose one way or another, mostly
without that knowledge. When I'm using e.g. C++, it's easy:
something like mantra "when in doubt, throw an exception" :-)
combined with RAII, works good (but not ideal, of course).


In C++ you can either throw exceptions or return integer codes in order to 
show exceptional situations. An error is, if you write in non-allocated 
memory areas.



So, I'll ask again: when I program in Haskell, what mechanism should I use?


I think this question was enough answered in general here in the thread 
and on the Wiki pages. I think we can better discuss concrete situations. 
Do you have a function in your code where you are uncertain whether to use 
error or exceptions?

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


Re: [Haskell-cafe] Re: Exception handling in numeric computations

2009-03-28 Thread Henning Thielemann


On Sat, 28 Mar 2009, Ketil Malde wrote:


Jonathan Cast  writes:


i.e., that application's file decoding result should be an Either
type that anticipates that the file encoding may be invalid.



This is pretty standard, I thought.  Do people write Haskell file input
methods that are undefined (`throw exceptions') on invalid inputs (e.g.,
do people use read to parse input from users or the file system[1])?


I often write parsers that either run successfully, or abort with an
exception.  I could of course return an Either type, but that would
mean the whole file would need to be parsed before any results could
be returned at all - which is a showstopper for streaming processing
of large files.


If you need a lazy parser with error reporting, I suggest 
Control.Monad.Exception.Asynchronous from the explicit-exception package.



Since at least my files are typically machine generated, a parse error
is either a programmer error in my parser, a programmer error in the
generating program, or an operator error (viz. the user running the
program on a completely different file type).


That's no excuse. You can never rely on proper file formatting since the 
user alter the file while you process it, delete it, or remove the disk it 
is stored on.

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


[Haskell-cafe] Re: Exception handling in numeric computations

2009-03-28 Thread Gregory Petrosyan
On Sat, Mar 28, 2009 at 10:53 AM, Ketil Malde  wrote:
> So the difference between an exception or an error type is mainly what
> you intend to do about it.  There's no point in wrapping divisions in
> Maybe unless you actually are able to do something useful to recover
> from a zero denominator.

That is exactly the point I was trying to make.

When I write a code, I can't say in advance, in what way it will be used.
So, for dealing with errors, I have to choose one way or another, mostly
without that knowledge. When I'm using e.g. C++, it's easy:
something like mantra "when in doubt, throw an exception" :-)
combined with RAII, works good (but not ideal, of course).

So, I'll ask again: when I program in Haskell, what mechanism should I use?

   Gregory
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: Exception handling in numeric computations

2009-03-28 Thread Ketil Malde
Jonathan Cast  writes:

>> i.e., that application's file decoding result should be an Either
>> type that anticipates that the file encoding may be invalid.

> This is pretty standard, I thought.  Do people write Haskell file input
> methods that are undefined (`throw exceptions') on invalid inputs (e.g.,
> do people use read to parse input from users or the file system[1])?

I often write parsers that either run successfully, or abort with an
exception.  I could of course return an Either type, but that would
mean the whole file would need to be parsed before any results could
be returned at all - which is a showstopper for streaming processing
of large files.

Since at least my files are typically machine generated, a parse error
is either a programmer error in my parser, a programmer error in the
generating program, or an operator error (viz. the user running the
program on a completely different file type).  In any case, I want the
program execution to halt and report the error as soon as possible.

So the difference between an exception or an error type is mainly what
you intend to do about it.  There's no point in wrapping divisions in
Maybe unless you actually are able to do something useful to recover
from a zero denominator.

-k
-- 
If I haven't seen further, it is by standing in the footprints of giants
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: Exception handling in numeric computations

2009-03-27 Thread Donn Cave
Quoth Henning Thielemann ,
> On Fri, 27 Mar 2009, Donn Cave wrote:
>
>> Quoth Jonathan Cast ,
>>
>>> An `error' is any condition where the correct response is for the
>>> programmer to change the source code :)
>>
>> That's a broad category, that overlaps with conditions where there
>> are one or more correct responses for the original program as well.
>>
>> If I throw exceptions within the type system, using IO or whatever,
>> and at some later time observe that I have caught one that would
>> have been better handled closer to its source, for example.  I've
>> already technically satisfied my requirement, since everything is
>> in an exception monad, but the exception is still a bug.
>
> I don't understand this one.

A lame attempt to demonstrate that "condition where [a] correct
response is to change the code" applies to too many cases to be
useful.  (And that there are no cases where [the only] correct
response is to change the code.)

>> Or if I catch an non-IO error using Control.Exception.catch (if I
>> were using ghc), and take advantage of the opportunity to release
>> locks, post various notices, etc. - I evidently have a bug, but I
>> also may need to have a programmed response for it.
>
> The usual example against clear separation of exceptions and errors is the 
> web server which catches 'error's in order to keep running. However, the 
> web server starts its parts as threads, and whenever one thread runs into 
> an 'error', it is terminated, just like an external shell program, that 
> terminates with a segmentation fault. So, yes an error might be turned 
> into an exception, but these are rare cases. In general it is hard or 
> impossible to correctly clean up after an error, because the error occured 
> due to something that you as programmer didn't respect. The "error 
> handler" could well make things worse by freeing memory that is already 
> deallocated and so on.

But you'd have to weigh that against the consequences of not continuing.

I can certainly see the attraction of the exception monad treatment
for anticipated errors.  It might tend to obscure a central computation
for the sake of handling a lot of weird little errors that may never
actually be encountered, and doesn't it occasionally have a problem
with making things strict that didn't already need to be?  but at least
it makes it easier to reason about the code in terms that include errors.

And I'm using nhc98 lately, so no Control.Exception.catch for me, but
if I had it, I'd use it, just like I wear a helmet when I ride my
bicycle or motorcycle.

Donn

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


Re: [Haskell-cafe] Re: Exception handling in numeric computations

2009-03-27 Thread Robert Greayer

Henning Thielemann  wrote:
> The usual example against clear separation of exceptions and errors is the 
> web server which catches 'error's in order to keep running. 
> However, the web server starts its parts as threads, and whenever one thread 
> runs into an 'error', it is terminated, just like an external shell
> program, that terminates with a segmentation fault. So, yes an error might be 
> turned into an exception, but these are rare cases. In 
> general it is hard or impossible to correctly clean up after an error, 
> because the error occured due to something that you as programmer
> didn't respect. The "error handler" could well make things worse by freeing 
> memory that is already deallocated and so on.

I don't see that as an argument against 'clear separation', really.  Having 
_some_ way of dealing an error (from within a program), in special 
circumstances doesn't preclude clearly separating how it's done from exception 
handling.  I always find it jarring when an HUnit test I've run tells me it 
encountered an 'exception', when I'm testing pure code (nevertheless I'd also 
find it annoying if the entire test run terminated because of a failed pattern 
match).

With respect to the last point - isn't proving that a given program can't 
corrupt its own RTS possible, even in the presence of errors?



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


[Haskell-cafe] Re: Exception handling in numeric computations

2009-03-27 Thread John Lato
>
> Message: 8
> Date: Fri, 27 Mar 2009 10:41:05 -0700
> From: Jonathan Cast 
> Subject: Re: [Haskell-cafe] Re: Exception handling in numeric
>        computations
> To: Gregory Petrosyan 
> Cc: haskell-cafe@haskell.org
> Message-ID: <1238175665.20367.12.ca...@jcchost>
> Content-Type: text/plain; charset=utf-8
>
> On Fri, 2009-03-27 at 20:38 +0300, Gregory Petrosyan wrote:
>> On Fri, Mar 27, 2009 at 7:31 PM, Donn Cave  wrote:
>> > Quoth John Lato ,
>> >
>> >> An exception is caused by some sort of interaction with the run-time
>> >> system (frequently a hardware issue).  The programmer typically can't
>> >> check for these in advance, but can only attempt to recover after
>> >> they've happened.
>> >>
>> >> An error is some sort of bug that should be fixed by the programmer.
>> >
>> > I have never felt that I really understood that one.
>>
>> Me too :-)
>>
>> BTW, John, how often do you encounter _hardware_ issues compared to "errors"?
>
> Can't speak for anyone else, but I usually encounter hardware issues
> just before I replace the hardware...

This is getting confusing with two "John"'s replying.

For myself, I do not encounter hardware issues often at all (unless
you count buggy drivers).  They are the exceptional condition.

>
>> Is an "out of memory" thing an error or exception?
>> You will say "exception, for sure", wouldn't you? :-)
>
> No.  GHC possesses an out-of-memory exception that (IIRC) it never
> throws, because it's simply not worth trying to recover from heap
> exhaustion.  Maybe 20 years ago it was, but these days a program that
> manages to exhaust space is almost certainly either buggy or poorly
> optimized.

I would have said exception, although I agree with the assessment that
it's not worth trying to recover from.

>
> An `error' is any condition where the correct response is for the
> programmer to change the source code :)
>
>> And if it is a
>> result of applying
>> known-to-be-very-memory-hungry algorithms to non-trivial input? Looks like
>> programmer's error, doesn't it?
>
> See above.

Due to their brevity, I sometimes find it difficult to understand
Jonathan's replies.  So at the risk of putting words in his mouth, I
will take an attempt to explain this further.  Keep in mind these are
my words, not his, and it's possible I have completely misunderstood
his point since I've only been using Haskell intensively for about a
year (and I have no formal CS training, and other biographical points
apply as well).

Running out of memory is an exceptional condition.  Doing something
that is likely to cause memory exhaustion is a programming error,
because it was the wrong solution to the problem.  Memory exhaustion,
the exceptional condition, is an end result of making the programming
error.  In this case (but not all), it is possible to treat the
symptoms by handling the exception, but the general solution is to
avoid the problem in the first place.

>
>> And I think I can provide lots of similar examples.
>>
>> If there exists separation between errors and exceptions, it should be
>> very strong
>> and evident — otherwise "casual programmers" like myself will need to
>> stare at the
>> ceiling every time they write something to decide what suits best.
>

I am not sure when I would every throw an exception in Haskell code,
short of re-raising from a handler.  Things that I would have used
exceptions for in C-sharp can be handled explicitly with Maybe or
Either, a style that I greatly prefer.

John

> Protip: try pacing instead of staring at the ceiling.
>
> jcc
>
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


[Haskell-cafe] Re: Exception handling in numeric computations

2009-03-27 Thread John Lato
> From: Donn Cave 
> Quoth John Lato ,
>
>> An exception is caused by some sort of interaction with the run-time
>> system (frequently a hardware issue).  The programmer typically can't
>> check for these in advance, but can only attempt to recover after
>> they've happened.
>>
>> An error is some sort of bug that should be fixed by the programmer.
>
> I have never felt that I really understood that one.

Honestly, me neither, until recently.  I'm only barely starting to
understand it, and I do think there's a great deal of overlap.  Even
if an error is a bug that can be fixed by the programmer, certain
exceptional situations can also be fixed by the programmer by handling
the exception, even if they can't be detected in advance.

In general I would say that I agree with JCC's responses.

>
> What about invalid inputs?  Say someone encounters a disk full error,
> and the resulting partly written file is now unreadable data for its
> intended application because of an invalid file encoding?  Is that
> an exception, or a bug that should be fixed?
>
> My guess is that you'll say it's a bug, i.e., that application's
> file decoding result should be an Either type that anticipates that
> the file encoding may be invalid.

Not necessarily.  I would be satisfied with a Maybe :)  I've
encountered malformed data frequently enough that any decoders I write
(and I have done so recently) would anticipate invalid data.

>
> I will also guess if the file is unreadable because of an external
> I/O problem like no read access to file or filesystem, you would
> similarly expect this to be treated like that - I mean, ideally, e.g.,
> hGetLine :: Handle -> IO (Either IOError String)

Not necessarily, but possibly.  The big difference, of course, is that
decoding can be a pure operation, while reading never is.

I personally wouldn't mind if hGetLine had the type you give.  The way
I see it, there are two advantages to exceptions in this case.  The
first is that it's very easy for exceptions to trickle up and be
handled at a higher level.  The second 'advantage' is that the
programmer doesn't need to explicitly handle exceptions, whereas an
Either would require at least a pattern match to use the resulting
value.

John
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: Exception handling in numeric computations

2009-03-27 Thread Henning Thielemann


On Fri, 27 Mar 2009, Donn Cave wrote:


Quoth Jonathan Cast ,


An `error' is any condition where the correct response is for the
programmer to change the source code :)


That's a broad category, that overlaps with conditions where there
are one or more correct responses for the original program as well.

If I throw exceptions within the type system, using IO or whatever,
and at some later time observe that I have caught one that would
have been better handled closer to its source, for example.  I've
already technically satisfied my requirement, since everything is
in an exception monad, but the exception is still a bug.


I don't understand this one.


Or if I catch an non-IO error using Control.Exception.catch (if I
were using ghc), and take advantage of the opportunity to release
locks, post various notices, etc. - I evidently have a bug, but I
also may need to have a programmed response for it.


The usual example against clear separation of exceptions and errors is the 
web server which catches 'error's in order to keep running. However, the 
web server starts its parts as threads, and whenever one thread runs into 
an 'error', it is terminated, just like an external shell program, that 
terminates with a segmentation fault. So, yes an error might be turned 
into an exception, but these are rare cases. In general it is hard or 
impossible to correctly clean up after an error, because the error occured 
due to something that you as programmer didn't respect. The "error 
handler" could well make things worse by freeing memory that is already 
deallocated and so on.

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


Re: [Haskell-cafe] Re: Exception handling in numeric computations

2009-03-27 Thread Henning Thielemann


On Thu, 26 Mar 2009, John Lato wrote:


Henning T., FYI your constant advocacy has gotten at least one person
around to this view.


I'm glad that it is not (only) perceived as annoyance. :-)
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: Exception handling in numeric computations

2009-03-27 Thread Henning Thielemann
Jonathan Cast schrieb:

>> i.e., that application's
>> file decoding result should be an Either type that anticipates that
>> the file encoding may be invalid.
> 
> This is pretty standard, I thought.  Do people write Haskell file input
> methods that are undefined (`throw exceptions') on invalid inputs (e.g.,
> do people use read to parse input from users or the file system[1])?

With

  case reads str of
 [(x, "")] -> Just x
 _ -> Nothing

you are safe. (I think it's now available as maybeRead.)

In general, relying on a well-formed input file is an error. However, if
your program detects a format error in file input, it could throw an
exception. But this means that your program must be prepared for these
problems.

>> I will also guess if the file is unreadable because of an external
>> I/O problem like no read access to file or filesystem, you would
>> similarly expect this to be treated like that - I mean, ideally, e.g.,
>> hGetLine :: Handle -> IO (Either IOError String)
> 
> IO is an exception monad already.  I don't think there's an objection to
> throwing exceptions with throwIO and catching them in IO; my objection,
> at least, is to designing your program to throw exceptions from
> (ostensibly...) *pure* code and catch those in IO, in a live
> environment.

Actually, I really object to have exception handling built into IO
monad. Especially with extensible-exceptions package you can hide which
kinds of exceptions can occur in a piece of code, which is a bad thing.
When it comes to lazy I/O, which is problematic in itself, it is better
to have explicit exceptions (i.e. IO (Either IOError String)) on top of
exception-free IO. See the recent thread on safe lazy I/O:
   http://www.haskell.org/pipermail/haskell-cafe/2009-March/058205.html

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


Re: [Haskell-cafe] Re: Exception handling in numeric computations

2009-03-27 Thread Donn Cave
Quoth Jonathan Cast ,

> An `error' is any condition where the correct response is for the
> programmer to change the source code :)

That's a broad category, that overlaps with conditions where there
are one or more correct responses for the original program as well.

If I throw exceptions within the type system, using IO or whatever,
and at some later time observe that I have caught one that would
have been better handled closer to its source, for example.  I've
already technically satisfied my requirement, since everything is
in an exception monad, but the exception is still a bug.

Or if I catch an non-IO error using Control.Exception.catch (if I
were using ghc), and take advantage of the opportunity to release
locks, post various notices, etc. - I evidently have a bug, but I
also may need to have a programmed response for it.

Donn

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


Re: [Haskell-cafe] Re: Exception handling in numeric computations

2009-03-27 Thread Jonathan Cast
On Fri, 2009-03-27 at 20:38 +0300, Gregory Petrosyan wrote:
> On Fri, Mar 27, 2009 at 7:31 PM, Donn Cave  wrote:
> > Quoth John Lato ,
> >
> >> An exception is caused by some sort of interaction with the run-time
> >> system (frequently a hardware issue).  The programmer typically can't
> >> check for these in advance, but can only attempt to recover after
> >> they've happened.
> >>
> >> An error is some sort of bug that should be fixed by the programmer.
> >
> > I have never felt that I really understood that one.
> 
> Me too :-)
> 
> BTW, John, how often do you encounter _hardware_ issues compared to "errors"?

Can't speak for anyone else, but I usually encounter hardware issues
just before I replace the hardware...

> Is an "out of memory" thing an error or exception?
> You will say "exception, for sure", wouldn't you? :-)

No.  GHC possesses an out-of-memory exception that (IIRC) it never
throws, because it's simply not worth trying to recover from heap
exhaustion.  Maybe 20 years ago it was, but these days a program that
manages to exhaust space is almost certainly either buggy or poorly
optimized.

An `error' is any condition where the correct response is for the
programmer to change the source code :)

> And if it is a
> result of applying
> known-to-be-very-memory-hungry algorithms to non-trivial input? Looks like
> programmer's error, doesn't it?

See above.

> And I think I can provide lots of similar examples.
> 
> If there exists separation between errors and exceptions, it should be
> very strong
> and evident — otherwise "casual programmers" like myself will need to
> stare at the
> ceiling every time they write something to decide what suits best.

Protip: try pacing instead of staring at the ceiling.

jcc


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


Re: [Haskell-cafe] Re: Exception handling in numeric computations

2009-03-27 Thread Gregory Petrosyan
On Fri, Mar 27, 2009 at 7:31 PM, Donn Cave  wrote:
> Quoth John Lato ,
>
>> An exception is caused by some sort of interaction with the run-time
>> system (frequently a hardware issue).  The programmer typically can't
>> check for these in advance, but can only attempt to recover after
>> they've happened.
>>
>> An error is some sort of bug that should be fixed by the programmer.
>
> I have never felt that I really understood that one.

Me too :-)

BTW, John, how often do you encounter _hardware_ issues compared to "errors"?

Is an "out of memory" thing an error or exception?
You will say "exception, for sure", wouldn't you? :-) And if it is a
result of applying
known-to-be-very-memory-hungry algorithms to non-trivial input? Looks like
programmer's error, doesn't it?

And I think I can provide lots of similar examples.

If there exists separation between errors and exceptions, it should be
very strong
and evident — otherwise "casual programmers" like myself will need to
stare at the
ceiling every time they write something to decide what suits best.

Gregory
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: Exception handling in numeric computations

2009-03-27 Thread Jonathan Cast
On Fri, 2009-03-27 at 09:31 -0700, Donn Cave wrote:
> Quoth John Lato ,
> 
> > An exception is caused by some sort of interaction with the run-time
> > system (frequently a hardware issue).  The programmer typically can't
> > check for these in advance, but can only attempt to recover after
> > they've happened.
> >
> > An error is some sort of bug that should be fixed by the programmer.
> 
> I have never felt that I really understood that one.
> 
> What about invalid inputs?  Say someone encounters a disk full error,
> and the resulting partly written file is now unreadable data for its
> intended application because of an invalid file encoding?  Is that
> an exception, or a bug that should be fixed?

NB: Of course it's a bug: if the disk is full, the partially written
file should be discarded and the previous version retained.  I'm not
going to hold you accountable for Unix's bugs, though.

> My guess is that you'll say it's a bug,

I think you mean `exception' here.

> i.e., that application's
> file decoding result should be an Either type that anticipates that
> the file encoding may be invalid.

This is pretty standard, I thought.  Do people write Haskell file input
methods that are undefined (`throw exceptions') on invalid inputs (e.g.,
do people use read to parse input from users or the file system[1])?

> I will also guess if the file is unreadable because of an external
> I/O problem like no read access to file or filesystem, you would
> similarly expect this to be treated like that - I mean, ideally, e.g.,
> hGetLine :: Handle -> IO (Either IOError String)

IO is an exception monad already.  I don't think there's an objection to
throwing exceptions with throwIO and catching them in IO; my objection,
at least, is to designing your program to throw exceptions from
(ostensibly...) *pure* code and catch those in IO, in a live
environment.

> Does that make sense so far?

jcc

[1] This post should not be taken as an endorsement of the use of the
Read class for any purpose, nor as an endorsement of its continued
existence in the standard library.


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


Re: [Haskell-cafe] Re: Exception handling in numeric computations

2009-03-27 Thread Donn Cave
Quoth John Lato ,

> An exception is caused by some sort of interaction with the run-time
> system (frequently a hardware issue).  The programmer typically can't
> check for these in advance, but can only attempt to recover after
> they've happened.
>
> An error is some sort of bug that should be fixed by the programmer.

I have never felt that I really understood that one.

What about invalid inputs?  Say someone encounters a disk full error,
and the resulting partly written file is now unreadable data for its
intended application because of an invalid file encoding?  Is that
an exception, or a bug that should be fixed?

My guess is that you'll say it's a bug, i.e., that application's
file decoding result should be an Either type that anticipates that
the file encoding may be invalid.

I will also guess if the file is unreadable because of an external
I/O problem like no read access to file or filesystem, you would
similarly expect this to be treated like that - I mean, ideally, e.g.,
hGetLine :: Handle -> IO (Either IOError String)

Does that make sense so far?

Donn

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


[Haskell-cafe] Re: Exception handling in numeric computations

2009-03-27 Thread Jonathan Cast
On Fri, 2009-03-27 at 12:24 +, Chris Kuklewicz wrote:
> Jonathan Cast wrote:
> > Sure.  Which also points out that the original safeDiv wasn't actually
> > safe, since there's no guarantee of what evaluate will do with x and y.
> > (Actually, there's not much guarantee of what evaluate does anyway ---
> > just that any errors in e's definition get turned into exceptions by the
> > time evaluate e finishes running, or don't turn into exceptions at all).
> > 
> 
> That is not true if you mean "any errors" as "any and all errors".

No, that's not what I mean.  I just couldn't think of a good phrasing
for `errors that would prevent e from being evaluated to HNF'.  Which is
still a lousy phrasing.

jcc


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


Re: [Haskell-cafe] Re: Exception handling in numeric computations

2009-03-27 Thread John Lato
On Fri, Mar 27, 2009 at 10:01 AM, Gregory Petrosyan
 wrote:
> Thanks a lot for the answer!
>
> On Thu, Mar 26, 2009 at 4:36 PM, John Lato  wrote:
>> Languages with checked exceptions usually use them for two purposes:
>>
>> 1.  Exceptional conditions - disk full, CPU on fire, etc.
>> 2.  Error handling - invalid arguments to a function, attempt to
>> invert non-invertible matrix, etc.
>
> Is there any good rule someone can use to decide whether it is error
> or exception?
> For me, this is the most important thing, because IMHO you (as library
> writer) often can't
> say what is it, it's up to client of your code to decide.

An exception is caused by some sort of interaction with the run-time
system (frequently a hardware issue).  The programmer typically can't
check for these in advance, but can only attempt to recover after
they've happened.

An error is some sort of bug that should be fixed by the programmer.

There is some overlap for certain cases, notably divide by 0.
Dividing by 0 is an error, because it's something that the program
should never do, and it can be detected and dealt with by the
programmer in advance.  However most systems allow the divide function
to be called with a 0 denominator.  The function has a precondition,
meaning the onus is on the programmer to not do it, however this is
not enforced by the language.  If a program does this in error, the
result is an exception because the result is not a valid number (this
is codified with NaN for IEEE floats).  In this case, a programming
error results in an exception.  The proper solution is to fix the
source of the problem, the error, instead of trying to clean up the
results.

>
>> Henning T., FYI your constant advocacy has gotten at least one person
>> around to this view.
>
> Can you please provide me some links about error/exception separation?

http://haskell.org/haskellwiki/Error
http://haskell.org/haskellwiki/Exception
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


[Haskell-cafe] Re: Exception handling in numeric computations

2009-03-27 Thread Chris Kuklewicz

Jonathan Cast wrote:

Sure.  Which also points out that the original safeDiv wasn't actually
safe, since there's no guarantee of what evaluate will do with x and y.
(Actually, there's not much guarantee of what evaluate does anyway ---
just that any errors in e's definition get turned into exceptions by the
time evaluate e finishes running, or don't turn into exceptions at all).



That is not true if you mean "any errors" as "any and all errors".

The 'evaluate' operation only forces the argument into weak head normal form 
(WHNF) not normal form (NF).  Thus 'evaluate' may succeed and then its return 
value could be examined further and only then trigger an exception.


I could easily define a new "Integral" type where WHNF is not NF and demonstrate 
the problem.


The solution is to use 'evaluate' only on known primitive types like Int, or on 
polymorphic data constrained to be NFDATA and use the 'rnf' strategy within the 
call to 'evaluate'.


--
Chris

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


Re: [Haskell-cafe] Re: Exception handling in numeric computations

2009-03-27 Thread Gregory Petrosyan
Thanks a lot for the answer!

On Thu, Mar 26, 2009 at 4:36 PM, John Lato  wrote:
> Languages with checked exceptions usually use them for two purposes:
>
> 1.  Exceptional conditions - disk full, CPU on fire, etc.
> 2.  Error handling - invalid arguments to a function, attempt to
> invert non-invertible matrix, etc.

Is there any good rule someone can use to decide whether it is error
or exception?
For me, this is the most important thing, because IMHO you (as library
writer) often can't
say what is it, it's up to client of your code to decide.

> Henning T., FYI your constant advocacy has gotten at least one person
> around to this view.

Can you please provide me some links about error/exception separation?

Gregory
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: Exception handling in numeric computations

2009-03-26 Thread Jonathan Cast
On Thu, 2009-03-26 at 21:57 -0400, wren ng thornton wrote:
> Jonathan Cast wrote:
> > Xiao-Yong Jin wrote:
> > > > Xiao-Yong Jin wrote:
> > > > > So I have another question.  Is the following function safe
> > > > > and legitimate?
> > > > >
> > > > >> safeDiv :: (Exception e, Integral a) =>
> > > > >>a -> a -> Either e a
> > > > >> safeDiv x y = unsafePerformIO . try . evaluate $ div x y
> > >
> > >> safeDiv' :: (Exception e, Integral a) =>
> > >> a -> a -> Either e a
> > >> safeDiv' _ 0 = Left e
> > >> safeDiv' x y = Right $ div x y
> > 
> > [...]
> > Other than that, I think the imprecise exceptions paper guarantees that
> > these two functions are equivalent (albeit unwisely: see below).
> 
> I don't think so. The evaluation of x and y may throw errors before we 
> get around to div.

Sure.  Which also points out that the original safeDiv wasn't actually
safe, since there's no guarantee of what evaluate will do with x and y.
(Actually, there's not much guarantee of what evaluate does anyway ---
just that any errors in e's definition get turned into exceptions by the
time evaluate e finishes running, or don't turn into exceptions at all).

> * safeDiv' will evaluate y (to pattern match against 0) and may return 
> an error, e, whereas safeDiv will return Left e if div is strict in y.
> 
> * safeDiv' postpones evaluating x and so may return Right e, whereas 
> safeDiv will return Left e if div is strict in x.

jcc


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


Re: [Haskell-cafe] Re: Exception handling in numeric computations

2009-03-26 Thread wren ng thornton

Jonathan Cast wrote:

Xiao-Yong Jin wrote:
> > Xiao-Yong Jin wrote:
> > > So I have another question.  Is the following function safe
> > > and legitimate?
> > >
> > >> safeDiv :: (Exception e, Integral a) =>
> > >>a -> a -> Either e a
> > >> safeDiv x y = unsafePerformIO . try . evaluate $ div x y
>
>> safeDiv' :: (Exception e, Integral a) =>
>> a -> a -> Either e a
>> safeDiv' _ 0 = Left e
>> safeDiv' x y = Right $ div x y

[...]
Other than that, I think the imprecise exceptions paper guarantees that
these two functions are equivalent (albeit unwisely: see below).


I don't think so. The evaluation of x and y may throw errors before we 
get around to div.


* safeDiv' will evaluate y (to pattern match against 0) and may return 
an error, e, whereas safeDiv will return Left e if div is strict in y.


* safeDiv' postpones evaluating x and so may return Right e, whereas 
safeDiv will return Left e if div is strict in x.



--
Live well,
~wren
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: Exception handling in numeric computations

2009-03-26 Thread Claus Reinke

safeDiv :: (Exception e, Integral a) =>
   a -> a -> Either e a
safeDiv x y = unsafePerformIO . try . evaluate $ div x y


I just want to know, from a theoretical point of view,
whether this 'safeDiv' in above definition is the same as


safeDiv' :: (Exception e, Integral a) =>
a -> a -> Either e a
safeDiv' _ 0 = Left e
safeDiv' x y = Right $ div x y


No. Firstly, safeDiv' doesn't compile!-) Then, if you replace
'e' by 'DivideByZero' and adjust the types:

   *Main> safeDiv 1 (throw Overflow)
   Left arithmetic overflow
   *Main> safeDiv' 1 (throw Overflow)
   *** Exception: arithmetic overflow

Try ':info ArithException' for more in the same group. You
could use other functions in Control.Exceptions to get more
control about which exceptions you want to handle and how,
but so far, there is no indication that 'unsafePerformIO' is
the right hammer to use here..

Claus

-- unsagePerformIO: some things are just not wise to do

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


Re: [Haskell-cafe] Re: Exception handling in numeric computations

2009-03-26 Thread Jonathan Cast
On Thu, 2009-03-26 at 14:23 -0400, Xiao-Yong Jin wrote:
> Henning Thielemann  writes:
> 
> > On Thu, 26 Mar 2009, Xiao-Yong Jin wrote:
> >
> >> So I have another question.  Is the following function safe
> >> and legitimate?
> >>
> >>> safeDiv :: (Exception e, Integral a) =>
> >>>a -> a -> Either e a
> >>> safeDiv x y = unsafePerformIO . try . evaluate $ div x y
> >>
> >> I believe it should be okay to use this 'safeDiv'.  What do
> >
> > I think that question is wrong way around. The real question is, why
> > do you want to solve your problem using unsafePerformIO?
> 
> I just want to know, from a theoretical point of view,
> whether this 'safeDiv' in above definition is the same as
> 
> > safeDiv' :: (Exception e, Integral a) =>
> > a -> a -> Either e a
> > safeDiv' _ 0 = Left e
> > safeDiv' x y = Right $ div x y

You need some sort of type case here to make sure your first case
matches only if e is the right type for divide-by-zero errors (too lazy
to look it up atm).  Alternatively, you could replace your type variable
e with the actual exception type you want, here and in the
unsafePerformIO version.

Other than that, I think the imprecise exceptions paper guarantees that
these two functions are equivalent (albeit unwisely: see below).

> For the question why do I want to do that, I am not sure.  I
> guess if the function which has an error call inside is
> provided by other library package, and I don't have a clear
> and easy way to tell whether the function will make the
> error call or not, it would be easy just to make a wrapper
> like that.

It might be easy, but if you didn't have a lot of insight into the
function's behavior, then it would be difficult to tell whether it's
really going to call error or whether it's going to go off into an
infinite loop.  (Consider the (slow) definition

x ^ n | n == 0= 1
  | n <  0= error "Negative exponents require ^^"
  | otherwise = x * x ^ (n - 1)

Now consider what happens if the library function forgets the second
case.  Your wrapper isn't safe anymore!)

I can see only two cases where a library function could call error
sometimes, and you wouldn't have a good feel for when:

 a) The function is calling error on exceptions.  You should bug the
library author to put the function into an exception monad instead.
Devil-may-care users can use

either (error . show) id

to turn exceptions into errors.

 b) The function has explicit pre-conditions, which you don't
understand.  You shouldn't pass arguments to a function that violate its
pre-conditions (ever!); if you don't understand those preconditions well
enough to test them in Haskell code, you might not understand them well
enough to make sure your code is calling the function correctly.  So you
might want to study the preconditions a little more.

> It's also a possible situation that I don't know
> how to test the input to a foreign function call.

FFI calls cannot throw Haskell exceptions.

jcc


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


Re: [Haskell-cafe] Re: Exception handling in numeric computations

2009-03-26 Thread Xiao-Yong Jin
Henning Thielemann  writes:

> On Thu, 26 Mar 2009, Xiao-Yong Jin wrote:
>
>> So I have another question.  Is the following function safe
>> and legitimate?
>>
>>> safeDiv :: (Exception e, Integral a) =>
>>>a -> a -> Either e a
>>> safeDiv x y = unsafePerformIO . try . evaluate $ div x y
>>
>> I believe it should be okay to use this 'safeDiv'.  What do
>
> I think that question is wrong way around. The real question is, why
> do you want to solve your problem using unsafePerformIO?

I just want to know, from a theoretical point of view,
whether this 'safeDiv' in above definition is the same as

> safeDiv' :: (Exception e, Integral a) =>
> a -> a -> Either e a
> safeDiv' _ 0 = Left e
> safeDiv' x y = Right $ div x y

For the question why do I want to do that, I am not sure.  I
guess if the function which has an error call inside is
provided by other library package, and I don't have a clear
and easy way to tell whether the function will make the
error call or not, it would be easy just to make a wrapper
like that.  It's also a possible situation that I don't know
how to test the input to a foreign function call.
-- 
c/*__o/*
<\ * (__
*/\  <
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


[Haskell-cafe] Re: Exception handling in numeric computations

2009-03-26 Thread John Lato
> Message: 15
> From: Xiao-Yong Jin 
> John Lato  writes:
>
> So I have another question.  Is the following function safe
> and legitimate?
>
>> safeDiv :: (Exception e, Integral a) =>
>>            a -> a -> Either e a
>> safeDiv x y = unsafePerformIO . try . evaluate $ div x y
>
> I believe it should be okay to use this 'safeDiv'.  What do
> you think?

Your question is unclear.  Are you asking if this function can be
safely used with current Haskell standards and implementations or are
you asking should the Haskell specification make a guarantee that this
function will do what you want?

I would answer "no" either way, but for different reasons.  Common to
both is: Don't use unsafe* functions unless you can prove that your
usage is safe.  That is proof as in mathematical usage; it must be
rigorous and complete.

John Lato
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: Exception handling in numeric computations

2009-03-26 Thread Henning Thielemann


On Thu, 26 Mar 2009, Xiao-Yong Jin wrote:


So I have another question.  Is the following function safe
and legitimate?


safeDiv :: (Exception e, Integral a) =>
   a -> a -> Either e a
safeDiv x y = unsafePerformIO . try . evaluate $ div x y


I believe it should be okay to use this 'safeDiv'.  What do


I think that question is wrong way around. The real question is, why do 
you want to solve your problem using unsafePerformIO?

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


Re: [Haskell-cafe] Re: Exception handling in numeric computations

2009-03-26 Thread Xiao-Yong Jin
John Lato  writes:

> Even in Haskell this separation isn't absolute.  Programmer errors,
> such as dividing by 0, can and do lead to exceptional conditions.  The
> proper way to handle dividing by 0 is to not do it in the first place,
> but if it happens because of a programming error, you've got an
> exception.  Unfortunately this encourages programmers to think that
> handling the exception is the proper way to deal with this condition,
> but it isn't.

So I have another question.  Is the following function safe
and legitimate?

> safeDiv :: (Exception e, Integral a) =>
>a -> a -> Either e a
> safeDiv x y = unsafePerformIO . try . evaluate $ div x y

I believe it should be okay to use this 'safeDiv'.  What do
you think?
-- 
c/*__o/*
<\ * (__
*/\  <
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: Exception handling in numeric computations

2009-03-26 Thread John Lato
On Wed, Mar 25, 2009 at 7:02 PM, Gregory Petrosyan
 wrote:
> First of all, thanks everybody for the discussion -- very interesting to read!
>
> Apologies if this is off-topic a bit.
>
> While reading, I have a feeling that proposed solutions are somewhat similar
> to checked exceptions. And IMO they turned out to be more harmful than useful.

Do you mean checked exceptions, or the proposed solutions?  IMO the
problem with checked exceptions is that they conflate two ideas by
trying to use the existing exception framework to do something that
can't otherwise be done by the language.  This leads to something that
doesn't work well for either use.

Languages with checked exceptions usually use them for two purposes:

1.  Exceptional conditions - disk full, CPU on fire, etc.
2.  Error handling - invalid arguments to a function, attempt to
invert non-invertible matrix, etc.

In the first case, checked exceptions are a pain because there are so
many different possible exceptional conditions to enumerate.  Or
alternatively you have an IOException that can be one of hundreds of
actual exceptional conditions.  This is exactly what regular
exceptions are for, and in general there's little that can be done
except terminate the program, except for certain special cases
explicitly handled by the programmer.

For the second case, checked exceptions actually work okay IMO.  The
syntax is a bit clunky, but they serve the purpose.  That is, they
specifically indicate what functions may fail and the failure mode.
They also allow calling code to either handle it there or pass the
error up to a higher level as appropriate.  The syntax is usually
ugly, though.

Combining these two functions into one tool gives suboptimal results.
If you're using checked exceptions for error handling, then you also
end up using them for exception handling.  That means you have
IOException thrown by just about everything (and in theory any
function in an imperative language could have an IOException due to
hardware fault), leading to complex exception handlers with a half
dozen case statements.

There are a few reasons why Haskell's approach is (or at least can be)
different.  Compare the error handling models.  Checked exceptions are
bolted on to an existing tool attempting to make it serve a different
purpose.  It seems like a good idea, but ends up being painful because
the two uses are at cross purposes.  Instead of using a specific
implementation and trying to alter it for another use, Haskell uses a
very general facility, the type system, to solve one problem, and
keeps the exception handling facility separate.

Haskell's syntax for error handling is also much nicer.  Nobody likes
using methods that could possibly throw a dozen different exceptions,
some of which are IOException and some are not.

Actually, Haskell IO makes a big difference to this.  Conceptually,
you could think of Haskell functions as purely mathematical
constructs.  In particular, they can't interact with the physical
world.  This is true even for the IO monad.  Exceptional conditions
only arise when the Haskell runtime actually tries to *evaluate* an IO
function.  As a consequence exceptional conditions only arise as part
of IO actions, and can only be handled by IO actions (because they're
interacting with the run-time environment).  This distinction makes it
possible to enforce a separation between exceptions and error
conditions, which is generally not possible in imperative languages
where a function could fail either for a computational reason (divide
by 0) or a hardware/runtime fault.

Even in Haskell this separation isn't absolute.  Programmer errors,
such as dividing by 0, can and do lead to exceptional conditions.  The
proper way to handle dividing by 0 is to not do it in the first place,
but if it happens because of a programming error, you've got an
exception.  Unfortunately this encourages programmers to think that
handling the exception is the proper way to deal with this condition,
but it isn't.

I've only recently come around to the camp of treating exception
handling and errors separately, so some of these thoughts may be a bit
loose for the moment.  In particular my thoughts from the above
paragraph have only recently become clear.

Henning T., FYI your constant advocacy has gotten at least one person
around to this view.

Cheers,
John Lato
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


[Haskell-cafe] Re: Exception handling in numeric computations

2009-03-25 Thread Xiao-Yong Jin
John Lato  writes:

>> Yes, I know, it's not really complicate to rewrite the above
>> code.  But, what do I really gain from this rewrite?
>
> Apologies if this discussion has moved on, but I wanted to comment on this.
>

Thanks for elaborating it more.

>
> You gain correctness.  Any functions that need to be
>rewritten in this
> case should be rewritten anyway, because they're already wrong.  Your
> function ff can fail for certain inputs.  This statement:
>>> | It is impractical to use method (a),
>>> | because not every function that uses 'invMat' knows how to
>>> | deal with 'invMat' not giving an answer.  So we need to use
>>> | method (b), to use monad to parse our matrix around.
>
> is conceptually wrong.  What does it mean to multiply the inverse of a
> non-invertible matrix by a scalar?  Obviously this is nonsensical.  If
> a computation can fail (as this can), the type of the function should
> reflect it.  The above functions
>
>>> f1 = scalarMult 2 . invMat
>>> f2 l r = l `multMat` invMat r
>
> should be
>
> f1 :: Matrix -> Maybe Matrix
> f1 = fmap (scalarMult 2) . invMat
>
> f2 :: Matrix -> Matrix -> Maybe Matrix
> f2 l r = fmap (multMat l) $ invMat r
>
> Of course these could be written with Control.Applicative as well:
>
> f1 m = scalarMult 2 <$> invMat m
> f2 l r = multMat l <$> invMat r
>
>
>>> ff :: Matrix -> Matrix -> YetAnotherBiggerMonad Matrix
>>> ff x y = let ff' = f1 x + f2 y
>  ...
>  in scalarMult (1/2) ff'
>
> (I think you may be missing an argument to f2 here.)
>
> This computation can fail as well, if the constituent parts fail.  The
> separate parts can be combined with applicative style:
>
> ff :: Matrix -> Matrix -> Maybe Matrix
> ff x y = scalarMult (1/2) <$> ( (+) <$> f1 x <*> f2 y)
>
> Compare this to the same code using monadic Maybe:
>
> ff :: Matrix -> Matrix -> Maybe Matrix
> ff x y = do
>   x' <- f1 x
>   y' <- f2 y
>   scalarMult (1/2) $ x' + y'
>
> You gain clarity and brevity.  Both examples are shorter and easier to
> understand because you aren't messing with all the plumbing of error
> handling using exceptions, although I find the Applicative version
> especially clear.  If you would like to keep track of why a
> computation failed, then use Either instead of Maybe with the Left
> carrying a reason for failure (e.g. NonInvertibleMatrix)
>
> Finally, you gain safety.  When you use a function f1 :: Matrix ->
> Matrix, you can be assured that you will get an actual, meaningful
> answer.  If you use a function f2 :: Matrix -> Maybe Matrix, you know
> that you may not get a meaningful answer, and it is simple to handle
> at the appropriate level of your code.  I (and many other Haskell
> users) find this to be conceptually cleaner than throwing dynamic
> exceptions or using undefined.
>
> Incidentally, this is one reason why many experienced Haskellers like
> the applicative style.  It allows you to express your computations
> without obtrusive error handling mixed in.  It's also more general
> than monads, so can be applied in more instances.
>
> div (and other non-total functions in the Prelude like head), are also
> frequently considered ugly hacks.  Just because we're stuck with
> something from H98 doesn't mean that it's necessarily good or elegant
> (the fail monad method and Functor not being a superclass of Monad
> come to mind).  In some ways FP has moved on since Haskell was
> formalized.
>
> There is an alternative approach that I believe was suggested by
> somebody else on the list:
>
> newtype InvMatrix = Invert {unWrap :: Matrix}
>
> then you can do
> invertMatrix :: Matrix -> Maybe InvMatrix
> invertMatrix = fmap Invert . invMat
>
> If you put these in a separate module and export InvMatrix, unwrap,
> and invertMatrix, but not Invert, then the only way to create an
> InvMatrix is with invertMatrix, so any data of type InvMatrix is
> guaranteed to be invertible (and inverted from what you used to create
> it).
>
> Then your ff function becomes:
>
> ff :: InvMatrix -> InvMatrix -> Matrix
>
> the final value of the function could be InvMatrix if you can prove
> that it's invertible after your operations (although to be efficient,
> this would require exporting the Invert constructor and a proof from
> the programmer).  This keeps ff pure; you don't even have to deal with
> Maybe (although there are other ramifications to doing this that
> should be considered).
>
> John
>
>
>

-- 
c/*__o/*
<\ * (__
*/\  <
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


[Haskell-cafe] Re: Exception handling in numeric computations

2009-03-25 Thread John Lato
> Jake McArthur  writes:
>
>> Xiao-Yong Jin wrote:
>> | The problem is that there will be many functions using such
>> | a function to invert a matrix, making this inversion
>> | function return Either/Maybe or packing it in a monad is
>> | just a big headache.
>>
>> I disagree. If you try to take the inverse of a noninvertable matrix,
>> this is an *error* in your code. Catching an error you created in pure
>> code and patching it with chewing gum it is just a hack. A monadic
>> approach (I'm putting Either/Maybe under the same umbrella for brevity)
>> is the only solution that makes any sense to me, and I don't think it's
>> ugly as you are making it out to be.
>>
>
> Then, why is 'div' not of type 'a -> a -> ArithExceptionMonad a' ?
> Why does it throws this /ugly/ /error/ when it is applied to
> 0?  Why is it not using some beautiful
> 'ArithExceptinoMonad'?  Is 'Control.Exception' just pure
> /ugly/ and doesn't make any sense?
>
>>
>> | It is impractical to use method (a),
>> | because not every function that uses 'invMat' knows how to
>> | deal with 'invMat' not giving an answer.  So we need to use
>> | method (b), to use monad to parse our matrix around.
>> |
>> |> > invMat :: Matrix -> NumericCancerMonad Matrix
>> |
>> | It hides the exceptional nature of numerical computations
>> | very well, but it is cancer in the code.  Whenever any
>> | function wants to use invMat, it is mutated.  This is just
>> | madness.  You don't want to make all the code to be monadic
>> | just because of singularities in numeric calculation.
>>
>> For functions that don't know or don't care about failure, just use fmap
>> or one of its synonyms.
>>
>> ~    scalarMult 2 <$> invMat x
>>
>> See? The scalarMult function is pure, as it should be. There is no
>> madness here.
>
> Of course, 'scalarMult' is invulnerable and free of monad.
> But take a look at the following functions,
>
>> f1 = scalarMult 2 . invMat
>> f2 l r = l `multMat` invMat r
>> ff :: Matrix -> Matrix -> YetAnotherBiggerMonad Matrix
>> ff x y = do let ff' = f1 x + f2 y
>>             put . (addMat ff') . f1 << get
>>             tell $ f2 ff'
>>             when (matrixWeDontLike (f1 ff') $
>>                  throwError MatrixWeDontLike
>>             return $ scalarMult (1/2) ff'
>
> Yes, I know, it's not really complicate to rewrite the above
> code.  But, what do I really gain from this rewrite?

Apologies if this discussion has moved on, but I wanted to comment on this.

You gain correctness.  Any functions that need to be rewritten in this
case should be rewritten anyway, because they're already wrong.  Your
function ff can fail for certain inputs.  This statement:
>> | It is impractical to use method (a),
>> | because not every function that uses 'invMat' knows how to
>> | deal with 'invMat' not giving an answer.  So we need to use
>> | method (b), to use monad to parse our matrix around.

is conceptually wrong.  What does it mean to multiply the inverse of a
non-invertible matrix by a scalar?  Obviously this is nonsensical.  If
a computation can fail (as this can), the type of the function should
reflect it.  The above functions

>> f1 = scalarMult 2 . invMat
>> f2 l r = l `multMat` invMat r

should be

f1 :: Matrix -> Maybe Matrix
f1 = fmap (scalarMult 2) . invMat

f2 :: Matrix -> Matrix -> Maybe Matrix
f2 l r = fmap (multMat l) $ invMat r

Of course these could be written with Control.Applicative as well:

f1 m = scalarMult 2 <$> invMat m
f2 l r = multMat l <$> invMat r


>> ff :: Matrix -> Matrix -> YetAnotherBiggerMonad Matrix
>> ff x y = let ff' = f1 x + f2 y
 ...
 in scalarMult (1/2) ff'

(I think you may be missing an argument to f2 here.)

This computation can fail as well, if the constituent parts fail.  The
separate parts can be combined with applicative style:

ff :: Matrix -> Matrix -> Maybe Matrix
ff x y = scalarMult (1/2) <$> ( (+) <$> f1 x <*> f2 y)

Compare this to the same code using monadic Maybe:

ff :: Matrix -> Matrix -> Maybe Matrix
ff x y = do
  x' <- f1 x
  y' <- f2 y
  scalarMult (1/2) $ x' + y'

You gain clarity and brevity.  Both examples are shorter and easier to
understand because you aren't messing with all the plumbing of error
handling using exceptions, although I find the Applicative version
especially clear.  If you would like to keep track of why a
computation failed, then use Either instead of Maybe with the Left
carrying a reason for failure (e.g. NonInvertibleMatrix)

Finally, you gain safety.  When you use a function f1 :: Matrix ->
Matrix, you can be assured that you will get an actual, meaningful
answer.  If you use a function f2 :: Matrix -> Maybe Matrix, you know
that you may not get a meaningful answer, and it is simple to handle
at the appropriate level of your code.  I (and many other Haskell
users) find this to be conceptually cleaner than throwing dynamic
exceptions or using undefined.

Incidentally, this is one reason why many experienced Haskellers like
the applicative style.  It allows yo

Re: [Haskell-cafe] Re: Exception handling in numeric computations

2009-03-24 Thread Henning Thielemann


On Tue, 24 Mar 2009, Xiao-Yong Jin wrote:


Thanks for all the replies.  Now I understand more about
Exceptions and Errors.  I guess all I need is to compose a
larger monad, after all.  I need to learn how to make
two different stacks of monad transformers cooperate
seamlessly, though.


Until now it seems you only need Applicative functor. They can be combined 
in a more general way:

  
http://hackage.haskell.org/packages/archive/TypeCompose/0.6.4/doc/html/Control-Compose.html

See the instances:
  (Applicative g, Applicative f) => Applicative (g :. f)
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: Exception handling in numeric computations

2009-03-24 Thread Xiao-Yong Jin
Jake McArthur  writes:

> Xiao-Yong Jin wrote:
> | Then, why is 'div' not of type 'a -> a -> ArithExceptionMonad a' ?
> | Why does it throws this /ugly/ /error/ when it is applied to
> | 0?  Why is it not using some beautiful
> | 'ArithExceptinoMonad'?  Is 'Control.Exception' just pure
> | /ugly/ and doesn't make any sense?
>
> 'div' throws an error because dividing by zero is *programmer error*.
> *You* are supposed to make sure that you aren't dividing by zero.
>
> I differ from this decision in your case because, as you said, it is
> easier to check for the error condition in the function itself than to
> check it externally. This is fine, but because it's so hard to check
> externally, you have to tell the outside world whether there was an
> error or not. A functor/applicative/monad is the pure way to do this. An
> error is not.
>
> | Of course, 'scalarMult' is invulnerable and free of monad.
> | But take a look at the following functions,
> |
> |> f1 = scalarMult 2 . invMat
> |> f2 l r = l `multMat` invMat r
> |> ff :: Matrix -> Matrix -> YetAnotherBiggerMonad Matrix
> |> ff x y = do let ff' = f1 x + f2 y
> |> put . (addMat ff') . f1 << get
> |> tell $ f2 ff'
> |> when (matrixWeDontLike (f1 ff') $
> |>  throwError MatrixWeDontLike
> |> return $ scalarMult (1/2) ff'
> |
> | Yes, I know, it's not really complicate to rewrite the above
> | code.  But, what do I really gain from this rewrite?
>
> Code that is fully documented by its type, no harder to compose, more
> pure, and does what the programmer expects it to do.

Thanks for all the replies.  Now I understand more about
Exceptions and Errors.  I guess all I need is to compose a
larger monad, after all.  I need to learn how to make
two different stacks of monad transformers cooperate
seamlessly, though.

Thanks,
Xiao-Yong
-- 
c/*__o/*
<\ * (__
*/\  <
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: Exception handling in numeric computations

2009-03-24 Thread Jake McArthur

-BEGIN PGP SIGNED MESSAGE-
Hash: SHA1

Xiao-Yong Jin wrote:
| Then, why is 'div' not of type 'a -> a -> ArithExceptionMonad a' ?
| Why does it throws this /ugly/ /error/ when it is applied to
| 0?  Why is it not using some beautiful
| 'ArithExceptinoMonad'?  Is 'Control.Exception' just pure
| /ugly/ and doesn't make any sense?

'div' throws an error because dividing by zero is *programmer error*.
*You* are supposed to make sure that you aren't dividing by zero.

I differ from this decision in your case because, as you said, it is
easier to check for the error condition in the function itself than to
check it externally. This is fine, but because it's so hard to check
externally, you have to tell the outside world whether there was an
error or not. A functor/applicative/monad is the pure way to do this. An
error is not.

| Of course, 'scalarMult' is invulnerable and free of monad.
| But take a look at the following functions,
|
|> f1 = scalarMult 2 . invMat
|> f2 l r = l `multMat` invMat r
|> ff :: Matrix -> Matrix -> YetAnotherBiggerMonad Matrix
|> ff x y = do let ff' = f1 x + f2 y
|> put . (addMat ff') . f1 << get
|> tell $ f2 ff'
|> when (matrixWeDontLike (f1 ff') $
|>  throwError MatrixWeDontLike
|> return $ scalarMult (1/2) ff'
|
| Yes, I know, it's not really complicate to rewrite the above
| code.  But, what do I really gain from this rewrite?

Code that is fully documented by its type, no harder to compose, more
pure, and does what the programmer expects it to do.

- - Jake
-BEGIN PGP SIGNATURE-
Version: GnuPG v1.4.9 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iEYEARECAAYFAknJXpcACgkQye5hVyvIUKnTOwCgzqRC4i7eLgbOQW1r+u2NPhAQ
7NkAnRsOFE8uMWrB/TRxTfdP/+x35EZ8
=kCtc
-END PGP SIGNATURE-
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: Exception handling in numeric computations

2009-03-24 Thread Henning Thielemann


On Tue, 24 Mar 2009, Xiao-Yong Jin wrote:


Jake McArthur  writes:


Xiao-Yong Jin wrote:
| The problem is that there will be many functions using such
| a function to invert a matrix, making this inversion
| function return Either/Maybe or packing it in a monad is
| just a big headache.

I disagree. If you try to take the inverse of a noninvertable matrix,
this is an *error* in your code. Catching an error you created in pure
code and patching it with chewing gum it is just a hack. A monadic
approach (I'm putting Either/Maybe under the same umbrella for brevity)
is the only solution that makes any sense to me, and I don't think it's
ugly as you are making it out to be.



Then, why is 'div' not of type 'a -> a -> ArithExceptionMonad a' ?
Why does it throws this /ugly/ /error/ when it is applied to
0?


I think "throw" should be reserved to exceptions (although it is still 
strange English). Actually 'div x 0' is 'undefined', just like in 
mathematics. This is justified by the fact, that you can easily check 
whether the denominator is zero or not and it is expected that either you 
check the denominator before calling 'div' or that you proof that in your 
application the denominator is non-zero anyway and thus save repeated 
checks for zero at run-time. The deficiency is not in 'div' but in the 
type system, which does not allow to declare an Int to be non-zero. In 
contrast to that, it is not easily checked, whether a matrix is regular. 
Thus you may prefer a Maybe result.

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


[Haskell-cafe] Re: Exception handling in numeric computations

2009-03-24 Thread Xiao-Yong Jin
Daniel Yokomizo  writes:

> On Tue, Mar 24, 2009 at 1:27 PM, Xiao-Yong Jin  wrote:
>> Henning Thielemann  writes:
>>
>>> Try to never use exception handling for catching programming errors!
>>> Division by zero is undefined, thus a programming error when it
>>> occurs.
>>>  http://www.haskell.org/haskellwiki/Error
>>>  http://www.haskell.org/haskellwiki/Exception
>>>   I'm afraid, a Maybe or Either or Exceptional (see explicit-exception
>>> package) return value is the only way to handle exceptional return
>>> values properly. Maybe in the larger context of your problem zero
>>> denominators can be avoided? Then go this way.
>>
>> Using div is just an example I'm testing with what I read in
>> the book Real World Haskell.  The real thing I'm trying to
>> do is inverting a matrix.  Say, I want to write
>>
>>> invMat :: Matrix -> Matrix
>>
>> You won't be able to invert all the matrix, mathematically.
>> And computationally, even a larger set of matrix might fail
>> to be inverted because of the finite precision.  It is
>> relatively easier and more efficient to spot such a problem
>> within this 'invMat' function.  Because testing the
>> singularity of a matrix is equally hard as invert it.  So
>> all I can do when 'invMat' spot a singular matrix are
>>
>>  a) Return Either/Maybe to signal an error.
>>  b) Wrap it in a monad.
>>  c) Define a dynamic exception and throw it.
>
> In general if a function is partial we can either make it total by
> extending its range or restricting its domain. Also we can signal it
> using runtime or compile-time mechanisms. Options a & b are equivalent
> (i.e. extend the range, compile-time notification) and option c is
> also another way of extending the range, but using runtime
> notification.
>
> If we try the other approach, we need to express the totality of
> invMat by restricting its domain, so we can add, for example, a
> phantom type to Matrix to signal it is invertible. As you need to
> construct the Matrix before trying to invert it you can always make
> the constructors smart enough to bundle the Matrix with such
> properties. Of course there's need to do some runtime verifications
> earlier, but the clients of invMat are required to do the verification
> earlier or pass it to their clients (up to the level that can handle
> with this issue):
>
> data Invertible
> tryInvertible :: Matrix a -> Maybe (Matrix Invertible)
> invMat :: Matrix Invertible -> Matrix Invertible
>
>
> You could use different forms of evidence (e.g. phantom types, type
> classes) but the idea is the same.

This is theoretically sound, we can make a type 'Integer
Invertible' and make a 'safeDiv' to get rid of one of the
ArithException.  But as I said above, "testing the
singularity of a matrix is equally hard as inverting it",
doing it with matrix is more impractical than make 'div'
safe.  I don't mind my haskell code runs 6 times slower than
c++ code.  But I'm not ready to make it 10 times slower just
because I want to do something twice and it might as well be
useless most of the time.
-- 
c/*__o/*
<\ * (__
*/\  <
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: Exception handling in numeric computations

2009-03-24 Thread Luke Palmer
On Tue, Mar 24, 2009 at 3:28 PM, Luke Palmer  wrote:

> On Tue, Mar 24, 2009 at 3:14 PM, Xiao-Yong Jin wrote:
>
>> Jake McArthur  writes:
>>
>> > Xiao-Yong Jin wrote:
>> > | The problem is that there will be many functions using such
>> > | a function to invert a matrix, making this inversion
>> > | function return Either/Maybe or packing it in a monad is
>> > | just a big headache.
>> >
>> > I disagree. If you try to take the inverse of a noninvertable matrix,
>> > this is an *error* in your code. Catching an error you created in pure
>> > code and patching it with chewing gum it is just a hack. A monadic
>> > approach (I'm putting Either/Maybe under the same umbrella for brevity)
>> > is the only solution that makes any sense to me, and I don't think it's
>> > ugly as you are making it out to be.
>> >
>>
>> Then, why is 'div' not of type 'a -> a -> ArithExceptionMonad a' ?
>> Why does it throws this /ugly/ /error/ when it is applied to
>> 0?  Why is it not using some beautiful
>> 'ArithExceptinoMonad'?  Is 'Control.Exception' just pure
>> /ugly/ and doesn't make any sense?
>
>
> It's a proof obligation, like using unsafePerformIO.  It is "okay" to use
> unsafePerformIO when it exhibits purely functional semantics, but it's
> possible to use it incorrectly, and there is no ImpureSemanticsException.
> If you are being rigorous, you simply have to prove that the denominator
> will not be zero, rather than relying on it to be caught at runtime.  You
> can move the check to runtime easily:
>
> safeDiv x 0 = Nothing
> safeDiv x y = Just (x `div` y)
>
> Going the other way, from a runtime check to an obligation, is impossible.
>

(well, except for div x y = fromJust (safeDiv x y).. but the runtime check
is still there in terms of operation)
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Re: Exception handling in numeric computations

2009-03-24 Thread Luke Palmer
On Tue, Mar 24, 2009 at 3:14 PM, Xiao-Yong Jin  wrote:

> Jake McArthur  writes:
>
> > Xiao-Yong Jin wrote:
> > | The problem is that there will be many functions using such
> > | a function to invert a matrix, making this inversion
> > | function return Either/Maybe or packing it in a monad is
> > | just a big headache.
> >
> > I disagree. If you try to take the inverse of a noninvertable matrix,
> > this is an *error* in your code. Catching an error you created in pure
> > code and patching it with chewing gum it is just a hack. A monadic
> > approach (I'm putting Either/Maybe under the same umbrella for brevity)
> > is the only solution that makes any sense to me, and I don't think it's
> > ugly as you are making it out to be.
> >
>
> Then, why is 'div' not of type 'a -> a -> ArithExceptionMonad a' ?
> Why does it throws this /ugly/ /error/ when it is applied to
> 0?  Why is it not using some beautiful
> 'ArithExceptinoMonad'?  Is 'Control.Exception' just pure
> /ugly/ and doesn't make any sense?


It's a proof obligation, like using unsafePerformIO.  It is "okay" to use
unsafePerformIO when it exhibits purely functional semantics, but it's
possible to use it incorrectly, and there is no ImpureSemanticsException.
If you are being rigorous, you simply have to prove that the denominator
will not be zero, rather than relying on it to be caught at runtime.  You
can move the check to runtime easily:

safeDiv x 0 = Nothing
safeDiv x y = Just (x `div` y)

Going the other way, from a runtime check to an obligation, is impossible.


>
> >
> > | It is impractical to use method (a),
> > | because not every function that uses 'invMat' knows how to
> > | deal with 'invMat' not giving an answer.  So we need to use
> > | method (b), to use monad to parse our matrix around.
> > |
> > |> > invMat :: Matrix -> NumericCancerMonad Matrix
> > |
> > | It hides the exceptional nature of numerical computations
> > | very well, but it is cancer in the code.  Whenever any
> > | function wants to use invMat, it is mutated.  This is just
> > | madness.  You don't want to make all the code to be monadic
> > | just because of singularities in numeric calculation.
> >
> > For functions that don't know or don't care about failure, just use fmap
> > or one of its synonyms.
> >
> > ~scalarMult 2 <$> invMat x
> >
> > See? The scalarMult function is pure, as it should be. There is no
> > madness here.
>
> Of course, 'scalarMult' is invulnerable and free of monad.
> But take a look at the following functions,
>
> > f1 = scalarMult 2 . invMat
> > f2 l r = l `multMat` invMat r
> > ff :: Matrix -> Matrix -> YetAnotherBiggerMonad Matrix
> > ff x y = do let ff' = f1 x + f2 y
> > put . (addMat ff') . f1 << get
> > tell $ f2 ff'
> > when (matrixWeDontLike (f1 ff') $
> >  throwError MatrixWeDontLike
> > return $ scalarMult (1/2) ff'
>
> Yes, I know, it's not really complicate to rewrite the above
> code.  But, what do I really gain from this rewrite?
> --
>c/*__o/*
><\ * (__
>*/\  <
> ___
> Haskell-Cafe mailing list
> Haskell-Cafe@haskell.org
> http://www.haskell.org/mailman/listinfo/haskell-cafe
>
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


[Haskell-cafe] Re: Exception handling in numeric computations

2009-03-24 Thread Xiao-Yong Jin
Jake McArthur  writes:

> Xiao-Yong Jin wrote:
> | The problem is that there will be many functions using such
> | a function to invert a matrix, making this inversion
> | function return Either/Maybe or packing it in a monad is
> | just a big headache.
>
> I disagree. If you try to take the inverse of a noninvertable matrix,
> this is an *error* in your code. Catching an error you created in pure
> code and patching it with chewing gum it is just a hack. A monadic
> approach (I'm putting Either/Maybe under the same umbrella for brevity)
> is the only solution that makes any sense to me, and I don't think it's
> ugly as you are making it out to be.
>

Then, why is 'div' not of type 'a -> a -> ArithExceptionMonad a' ?
Why does it throws this /ugly/ /error/ when it is applied to
0?  Why is it not using some beautiful
'ArithExceptinoMonad'?  Is 'Control.Exception' just pure
/ugly/ and doesn't make any sense?

>
> | It is impractical to use method (a),
> | because not every function that uses 'invMat' knows how to
> | deal with 'invMat' not giving an answer.  So we need to use
> | method (b), to use monad to parse our matrix around.
> |
> |> > invMat :: Matrix -> NumericCancerMonad Matrix
> |
> | It hides the exceptional nature of numerical computations
> | very well, but it is cancer in the code.  Whenever any
> | function wants to use invMat, it is mutated.  This is just
> | madness.  You don't want to make all the code to be monadic
> | just because of singularities in numeric calculation.
>
> For functions that don't know or don't care about failure, just use fmap
> or one of its synonyms.
>
> ~scalarMult 2 <$> invMat x
>
> See? The scalarMult function is pure, as it should be. There is no
> madness here.

Of course, 'scalarMult' is invulnerable and free of monad.
But take a look at the following functions,

> f1 = scalarMult 2 . invMat
> f2 l r = l `multMat` invMat r
> ff :: Matrix -> Matrix -> YetAnotherBiggerMonad Matrix
> ff x y = do let ff' = f1 x + f2 y
> put . (addMat ff') . f1 << get
> tell $ f2 ff'
> when (matrixWeDontLike (f1 ff') $
>  throwError MatrixWeDontLike
> return $ scalarMult (1/2) ff'

Yes, I know, it's not really complicate to rewrite the above
code.  But, what do I really gain from this rewrite?
-- 
c/*__o/*
<\ * (__
*/\  <
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe