Re: [Haskell-cafe] exceptions vs. Either

2004-08-04 Thread Ketil Malde
MR K P SCHUPKE [EMAIL PROTECTED] writes:

 As for head, I think it's fine that it throws an error because it is
 specified to be defined for only non-empty lists.

 But surely it is better to encode this fact in the type system by
 useing a separate type for non-empty lists.

Yes, in principle.  But that means you still need to write more and
tedious code to deal with it.  

And there's a question how far you can practically get with this
approach.  Are you going to discard lists in favor of tuples, just
because the type systems can't verify that the index passed to (!!) is
witin range?

 A mechanism for a function to report the caller site would obliviate
 the need for all this ugliness

 Unfortunately the cost of this is prohabative as the call stack
 would have to contain backtrace information. Also due to lazy
 evaluation the 'call site' may not be what you expect.

AFAICS, this disadvantage is shared by all other schemes of labeling
call sites.  The only difference is that I want to do it automatically
(perhaps when a debug option is passed to the compiler)

I don't want it for all functions or anything, just the annoying,
small, and commonly used leaf functions.

 Here's what John Meacham had to say:

 ---
 Note that pattern matching rather than deconstruction functions have a
 number of benefits, not just relating to error messages, consider two
 functions which use the head of their argument.

 f xs = ... head xs ...=20
 g (x:_) = ... x ...

 now, g is superior to f in several ways,=20

I agree with this.  How about constructs like

  mins = map (head.sort)

Is 

   mins = map ((\(x:_)-x).sort)

still so superior?  Is it really necessary to sacrifice code clarity
just to get decent error messages?

And how do you extend this approach to 'read' and (!!)?

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


Re: [Haskell-cafe] exceptions vs. Either

2004-08-04 Thread MR K P SCHUPKE
Yes, in principle.  But that means you still need to write more and
tedious code to deal with it.

Just because code is tedious does not mean it is not necessary to
handle all corner cases. A robust application does not fail when
given unexpected input.

Are you going to discard lists in favor of tuples,

Of course not... You can actually define constrained datatypes where
the maximum length is a parameter of the type. Unfortunately in haskell
because these values have to be at the type level we end up encoding
them as Peano numbers... See Conor McBrides Faking It paper for
some examples of how to do this. Also see Oleg, Ralf and My paper
Stronly Typed Heterogeneous Lists to se how far you can get with
these techniques (we define a heterogeneous list that can be constrained
in many ways, including by length, or content type).

I guess in a way you are nearly right as these techniques fundamentaly
us binary products like (,) - but thats also exactly what any binary
constructor including ':' is anyway...

The only difference is that I want to do it automatically

My point was that you can manually label some functions, but to automatically
do it for all functions is going to cause big stack space problems - think
about recursive functions... or mutually recursive functions... 

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


Re: [Haskell-cafe] exceptions vs. Either

2004-08-04 Thread MR K P SCHUPKE

mins = map ((\(x:_)-x).sort)

maybe what you meant was:

case sort x of
   (x:_) - ... do whatever with x ...
   _ - ... do failure conition ...

As I said, if you can _guarantee_ non failure I guess head is okay, but the
fact that this thread started with the observation that the error produced
by head is difficault to track dow
n we must conclude that programmers make mistakes and cannot be trusted to
make such guarantees  Hence my suggestion to use the type system.

Effectively the 'case' forms a guarantee of non-emtyness for the stuff in 
the case... but you cannot pass this guarantee into functions like 'head'

Using the type system to encode such things allows this 'guarantee' to
be passed into functions... 

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


Re: [Haskell-cafe] exceptions vs. Either

2004-08-04 Thread David Roundy
On Tue, Aug 03, 2004 at 12:51:50PM +0200, Ketil Malde wrote:
 Is there any easy way (TH?) to amend these to output the line number
 of the offending caller?  It would be a great improvement to see
 something like
 
 Prelude.head : empty list in Foo.hs, line 4711
 
 since programs generally contain many, many calls to functions like
 these.  

I include the following file in most files (and always use the C
preprocessor):

import DarcsUtils ( bug )
#define impossible (bug $ Impossible case at ++__FILE__++:++show (__LINE__ :: 
Int)++ compiled ++__TIME__++ ++__DATE__)

#define fromJust (\m - case m of {Nothing - bug (fromJust error at 
++__FILE__++:++show (__LINE__ :: Int)++ compiled ++__TIME__++ ++__DATE__); Just 
x - x})

Here bug is a function that just calls error with a little prefix
explaining that there is a bug in darcs, and would the user please report
it.  Obviously, defining a head here would be just as easy, but I usually
have more trouble with fromJust, which in a few places gets called in
internal routines where I *should* know that the data structure has no
Nothings, but have been known to make mistakes.

I also catch all error exceptions and print a nicer error message, so I
use fail and error raw to indicate actual user errors.
-- 
David Roundy
http://www.abridgegame.org
___
Haskell-Cafe mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] exceptions vs. Either

2004-08-04 Thread Malcolm Wallace
Ketil Malde [EMAIL PROTECTED] writes:

 Hmm...if I run it through CPP and 
   #define HEAD (\x - if null x then error (__FILE__:__LINE__) else head x)
 is the __LINE__ resolved at the place of declaration or at the place of usage?

According to the C standard, at the position of /usage/ of the macro `HEAD'.

Incidentally, cpphs does not yet implement __FILE__ or __LINE__
replacements.  Is their usage widespread amongst Haskell users?

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


Re: [Haskell-cafe] exceptions vs. Either

2004-08-04 Thread Ketil Malde
MR K P SCHUPKE [EMAIL PROTECTED] writes:

 mins = map ((\(x:_)-x).sort)

 maybe what you meant was:

   case sort x of
  (x:_) - ... do whatever with x ...
  _ - ... do failure conition ...

No, I don't think so.  I only want the bug to be reported, and the
umatched pattern will do it nicely.

 Yes, in principle.  But that means you still need to write more and
 tedious code to deal with it.

 Just because code is tedious does not mean it is not necessary to
 handle all corner cases. A robust application does not fail when
 given unexpected input.

But if I use head, I should *know* that I never pass it an
empty list.  Whether head returns a Nothing or just crashes doesn't
matter, I have to go and fix my *design*, because it has a bug,
and not a corner case that should be handled.

 Are you going to discard lists in favor of tuples,

 Of course not... You can actually define constrained datatypes where
 the maximum length is a parameter of the type. 

The only difference is that I want to do it automatically

 My point was that you can manually label some functions, but to automatically
 do it for all functions is going to cause big stack space problems - think
 about recursive functions... or mutually recursive functions... 

Yes, of course.  So *my* point is that it would be really nice to
write small leaf functions like these with an implicit file/line
parameter that identified the caller site, in order to avoid
cluttering the code with them.

Okay, perhaps I'm not using the type system to its full extent, but I
think this is fairly common practice.  

An easy solution seems to be to use -cpp and add

   #define head (\(x:_)-x)

at the top of the relevant source files.  However, I'm not sure how to
make this work with the other difficult functions.  Another
alternative (basically emulating the GHC's behavior in the above case)
is

   #define head (\x - case x of {(x:_) - x; _ - error (head failed at 
++__FILE__++:++ show __LINE__)})

It seems difficult to generalize this, though.

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


Re: [Haskell-cafe] exceptions vs. Either

2004-08-04 Thread MR K P SCHUPKE
No, I don't think so.  I only want the bug to be reported   

I think preventing the bug using the type system if possible is a good
idea... something that should be encouraged!

and not a corner case that should be handled.

So if the list depends on user input is not the empty list a corner
case of the function on user input?

write small leaf functions like these with an implicit file/line

This is a good idea - If I have given the impression I am opposed to it 
then I have not expressed myself very well. I just think where this can
be avoided using the type system in the first place is an even better
idea. Design by contract is the way forward for large complex systems, 
and where that contract can be expressed using the type system is
a selling point for Haskell in such applications.

It seems difficult to generalize this, though.

Again for read you can use reads...

Sven Panne said:

reads is probably what you are looking for:

Prelude (reads :: ReadS Integer) 
[]
Prelude (reads :: ReadS Integer) a
[]
Prelude (reads :: ReadS Integer) 2
[(2,)]
Prelude (reads :: ReadS Integer) 123blah
[(123,blah)]


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


Re: [Haskell-cafe] exceptions vs. Either

2004-08-04 Thread Ketil Malde
David Roundy [EMAIL PROTECTED] writes:

 Here bug is a function that just calls error with a little prefix
 explaining that there is a bug in darcs, and would the user please report
 it.  Obviously, defining a head here would be just as easy,

Cool!  The basic trick is just to inline the actual function
defintions using CPP macros.  I've made macros for most of the
troublesome functions, but I can't get it to work for operators
(something like `(!!)` doesn't parse, it seems)  Any tricks?

Unless I'm overlooking something, I could have a file prelude.h
containing something like:

8--
import Prelude hiding (head,(!!),read)

#define head (\xs - case xs of { (x:_) - x ; _ - bug head __FILE__ __LINE__})
#define at (let {at (y:_) 0  = y; at (y:ys) n = at ys (n-1); at _ _ = bug at 
__FILE__ __LINE__} in \a x - at a x)
#define read (\s - case [ x | (x,t) - reads s, (,) - lex t] of { [x] - x ; _ 
- bug read __FILE__ __LINE__})
#define fromJust (\x - case x of Just a - a; Nothing - bug fromJust __FILE__ 
__LINE__)

bug c f l = error (Program error - illegal parameters to '++c++', file '++f++', 
line ++show l)
8--

and just #include prelude.h if/when I want better debugging.  No
expensive stack frames, no unwanted strictness, and no clutter.

Any comments?

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


Re: [Haskell-cafe] exceptions vs. Either

2004-08-04 Thread Ketil Malde
Ketil Malde [EMAIL PROTECTED] writes:

 Unless I'm overlooking something

Which I of course did.

 #define at (let {at (y:_) 0  = y; at (y:ys) n = at ys (n-1); at _ _ = bug at 
 __FILE__ __LINE__} in \a x - at a x)

No prize for spotting the bug here.

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


Re: [Haskell-cafe] exceptions vs. Either

2004-08-04 Thread Ketil Malde
Ketil Malde [EMAIL PROTECTED] writes:

 import Prelude hiding (head,(!!),read)

 Any comments?

Here's one: I thought this would make it difficult to have other
imports of Prelude, hiding other pieces of it (e.g. catch, to avoid
ambiguities with Control.Exception.catch)

(Also, the definition of 'bug' hinders forces the #include to be after
any imports, not sure it's better to have a separate module for it,
which would then need to be on the module search path)

(I seem to be mainly following up to my own posts, so if somebody
asks, I'll take this to a quiet corner at the -cafe :-) 

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


[Haskell-cafe] Re: exceptions vs. Either

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

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

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

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

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

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