Is "take" behaving correctly?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
62 messages Options
1234
Reply | Threaded
Open this post in threaded view
|

Is "take" behaving correctly?

PR Stanley
Hi
take 1000 [1..3] still yields [1,2,3]
I thought it was supposed to return an error.
Any ideas?
Thanks, Paul

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Is "take" behaving correctly?

Tim Chevalier
On 9/11/07, PR Stanley <[hidden email]> wrote:
> Hi
> take 1000 [1..3] still yields [1,2,3]
> I thought it was supposed to return an error.
> Any ideas?

No, that's the behavior for take specified in the Haskell 98 report:
http://haskell.org/onlinereport/standard-prelude.html
"-- take n, applied to a list xs, returns the prefix of xs of length n,
-- or xs itself if n > length xs."

Cheers,
Tim

--
Tim Chevalier * catamorphism.org * Often in error, never in doubt
"Modesty...is both alien and irrelevant to people who are happy in
themselves, in their beings, in their skins, their natures, their
capacities."--Anne Sayre
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Is "take" behaving correctly?

Brent Yorgey
In reply to this post by PR Stanley

On 9/11/07, PR Stanley <[hidden email]> wrote:
Hi
take 1000 [1..3] still yields [1,2,3]
I thought it was supposed to return an error.
Any ideas?
Thanks, Paul

If for some reason you want a version that does return an error in that situation, you could do something like the following:

take' n _ | (n <= 0) = []
take' n [] | (n > 0) = error "take': list too short"
           | otherwise = []
take' n (x:xs) = x : take' (n-1) xs

I'm not sure why you'd want that, though.  The standard implementation gracefully handles all inputs, and usually turns out to be what you want.  Really, if I were you, instead of making a version take' as above, I would just use the standard take but check for the length of the list in the places where it matters.

-Brent

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Is "take" behaving correctly?

PR Stanley
In reply to this post by Tim Chevalier
I suppose I'm thinking of head or tail - e.g. head [] or tail [].
I'm trying to write my own version of the find function. I have a few ideas but not quite sure which would be more suitable in the context of FP.
Any advice would be gratefully received - e.g. do I use recursion, list comprehension or what?
Thanks, Paul

At 00:08 12/09/2007, you wrote:
On 9/11/07, PR Stanley <[hidden email]> wrote:
> Hi
> take 1000 [1..3] still yields [1,2,3]
> I thought it was supposed to return an error.
> Any ideas?

No, that's the behavior for take specified in the Haskell 98 report:
http://haskell.org/onlinereport/standard-prelude.html
"-- take n, applied to a list xs, returns the prefix of xs of length n,
-- or xs itself if n > length xs."

Cheers,
Tim

--
Tim Chevalier * catamorphism.org * Often in error, never in doubt
"Modesty...is both alien and irrelevant to people who are happy in
themselves, in their beings, in their skins, their natures, their
capacities."--Anne Sayre

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Is "take" behaving correctly?

Don Stewart-2
In reply to this post by Brent Yorgey
byorgey:

>    On 9/11/07, PR Stanley <[1][hidden email]> wrote:
>
>      Hi
>      take 1000 [1..3] still yields [1,2,3]
>      I thought it was supposed to return an error.
>      Any ideas?
>      Thanks, Paul
>
>    If for some reason you want a version that does return an error in that
>    situation, you could do something like the following:
>
>    take' n _ | (n <= 0) = []
>    take' n [] | (n > 0) = error "take': list too short"
>               | otherwise = []
>    take' n (x:xs) = x : take' (n-1) xs

And we'd call it unsafeTake, just like unsafeFromJust and unsafeTail :-)

-- Don
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Is "take" behaving correctly?

Brent Yorgey

On 9/11/07, Don Stewart <[hidden email]> wrote:
byorgey:

>    On 9/11/07, PR Stanley <[1]prstanley@ntlworld.com> wrote:
>
>      Hi
>      take 1000 [1..3] still yields [1,2,3]
>      I thought it was supposed to return an error.
>      Any ideas?
>      Thanks, Paul
>
>    If for some reason you want a version that does return an error in that
>    situation, you could do something like the following:
>
>    take' n _ | (n <= 0) = []
>    take' n [] | (n > 0) = error "take': list too short"
>               | otherwise = []
>    take' n (x:xs) = x : take' (n-1) xs

And we'd call it unsafeTake, just like unsafeFromJust and unsafeTail :-)

-- Don

Hmm, that's funny, I don't recall ever hearing of those functions... =)

ooo, Don has a shiny new e-mail address!

-Brent

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Is "take" behaving correctly?

John Meacham
In reply to this post by Brent Yorgey
On Tue, Sep 11, 2007 at 07:38:18PM -0400, Brent Yorgey wrote:

> On 9/11/07, PR Stanley <[hidden email]> wrote:
> >
> > Hi
> > take 1000 [1..3] still yields [1,2,3]
> > I thought it was supposed to return an error.
> > Any ideas?
> > Thanks, Paul
>
>
> If for some reason you want a version that does return an error in that
> situation, you could do something like the following:
>
> take' n _ | (n <= 0) = []
> take' n [] | (n > 0) = error "take': list too short"
>            | otherwise = []
> take' n (x:xs) = x : take' (n-1) xs


you could also do something like

take' n xs = take n (xs ++ error "I want more!")


        John

--
John Meacham - ⑆repetae.net⑆john⑈
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Is "take" behaving correctly?

PR Stanley
In reply to this post by Don Stewart-2
Let me get this right, are you saying it's unsafe when it returns an error?
Paul

At 00:40 12/09/2007, you wrote:
byorgey:
>    On 9/11/07, PR Stanley <[1][hidden email]> wrote:
>
>      Hi
>      take 1000 [1..3] still yields [1,2,3]
>      I thought it was supposed to return an error.
>      Any ideas?
>      Thanks, Paul
>
>    If for some reason you want a version that does return an error in that
>    situation, you could do something like the following:
>
>    take' n _ | (n <= 0) = []
>    take' n [] | (n > 0) = error "take': list too short"
>               | otherwise = []
>    take' n (x:xs) = x : take' (n-1) xs

And we'd call it unsafeTake, just like unsafeFromJust and unsafeTail :-)

-- Don

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Is "take" behaving correctly?

Don Stewart-2
In reply to this post by PR Stanley
prstanley:
>    I suppose I'm thinking of head or tail - e.g. head [] or tail [].
>    I'm trying to write my own version of the find function. I have a few
>    ideas but not quite sure which would be more suitable in the context of
>    FP.
>    Any advice would be gratefully received - e.g. do I use recursion, list
>    comprehension or what?

Well, you want to filter all elements from a list that match a predicate,
and then return Just the first match, or Nothing?

        find :: (a -> Bool) -> [a] -> Maybe a

Checking the current behaviour:

        > find isSpace "haskell is fun"
        Just ' '

My first go would be something like this: ok, so let's start with 'filter':

        > filter Char.isSpace "haskell is fun"
        "  "

Good, then the natural translation to the Maybe type:

        > listToMaybe . filter isSpace $ "haskell is fun"
        Just ' '

And we're almost done. Just firing up QuickCheck:

        > quickCheck $ \p (xs :: [Int])  -> find p xs == listToMaybe (filter p xs)
        OK, passed 100 tests.

Seems ok.

I hope that gives some insight into the process of deriving Haskell
implementations by building up a pipeline of pieces.

-- Don
       
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Is "take" behaving correctly?

Don Stewart-2
In reply to this post by Brent Yorgey
byorgey:

>    On 9/11/07, Don Stewart <[1][hidden email]> wrote:
>
>      byorgey:
>      >    On 9/11/07, PR Stanley <[1]prstanley@[2]ntlworld.com> wrote:
>      >
>      >      Hi
>      >      take 1000 [1..3] still yields [1,2,3]
>      >      I thought it was supposed to return an error.
>      >      Any ideas?
>      >      Thanks, Paul
>      >
>      >    If for some reason you want a version that does return an error in
>      that
>      >    situation, you could do something like the following:
>      >
>      >    take' n _ | (n <= 0) = []
>      >    take' n [] | (n > 0) = error "take': list too short"
>      >               | otherwise = []
>      >    take' n (x:xs) = x : take' (n-1) xs
>
>      And we'd call it unsafeTake, just like unsafeFromJust and unsafeTail :-)
>
>      -- Don
>
>    Hmm, that's funny, I don't recall ever hearing of those functions... =)
>
>    ooo, Don has a shiny new e-mail address!
>

And a shiny new job in a shiny new city :-)

-- Don
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Is "take" behaving correctly?

Don Stewart-2
In reply to this post by PR Stanley
prstanley:
>    Let me get this right, are you saying it's unsafe when it returns an
>    error?

Partial functions may crash your program, so that's unsafe by some definitions, yep.
We have tools that analyse programs for such bugs, in fact (Neil's `catch' program).

-- Don
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Is "take" behaving correctly?

Derek Elkins
In reply to this post by Don Stewart-2
On Tue, 2007-09-11 at 16:48 -0700, Don Stewart wrote:

> byorgey:
> >    On 9/11/07, Don Stewart <[1][hidden email]> wrote:
> >
> >      byorgey:
> >      >    On 9/11/07, PR Stanley <[1]prstanley@[2]ntlworld.com> wrote:
> >      >
> >      >      Hi
> >      >      take 1000 [1..3] still yields [1,2,3]
> >      >      I thought it was supposed to return an error.
> >      >      Any ideas?
> >      >      Thanks, Paul
> >      >
> >      >    If for some reason you want a version that does return an error in
> >      that
> >      >    situation, you could do something like the following:
> >      >
> >      >    take' n _ | (n <= 0) = []
> >      >    take' n [] | (n > 0) = error "take': list too short"
> >      >               | otherwise = []
> >      >    take' n (x:xs) = x : take' (n-1) xs
> >
> >      And we'd call it unsafeTake, just like unsafeFromJust and unsafeTail :-)
> >
> >      -- Don
> >
> >    Hmm, that's funny, I don't recall ever hearing of those functions... =)
> >
> >    ooo, Don has a shiny new e-mail address!
> >
>
> And a shiny new job in a shiny new city :-)

In a   new country.

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Is "take" behaving correctly?

Mirko Rahn
In reply to this post by PR Stanley

> take 1000 [1..3] still yields [1,2,3]

You can think about take n as: Take as much as possible, but at most n  
elements. This behavior has some nice properties as turned out by  
others, but there are some pitfalls. We have

length . take n /= const n

in general, instead only

length . take n `elem` map const [0..n]

holds. Therefore head . length n is unsafe for all n, even strict  
positive ones. Moreover, it is easy to produce tricky code. Assume you  
want to know, whether the prefixes of length k are equal and write

pref_eq k xs ys = take k xs == take k ys

This seems to be a straightforward implementation with good  
properties. Now play a bit with it:

Prelude> pref_eq 3 "ab" "abc"
False
Prelude> pref_eq 3 "ab" "ab"
True
Prelude> map (pref_eq 3 "ab") $ Data.List.inits "abc"
[False,False,True,False]

Uhh, this is not what everybody expects at first glance. In particular, if

pref_eq k xs ys == False

then *not* necessarily

pref_eq k xs (init ys) == False.

As always, quickCheck is your friend to assure (or reject) such a property.

/BR
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Is "take" behaving correctly?

Conor McBride
In reply to this post by Brent Yorgey
Hi folks

On 12 Sep 2007, at 00:38, Brent Yorgey wrote:

>
> On 9/11/07, PR Stanley <[hidden email]> wrote: Hi
> take 1000 [1..3] still yields [1,2,3]
> I thought it was supposed to return an error.

[..]

> If for some reason you want a version that does return an error in  
> that situation, you could do something like the following:
>
> take' n _ | (n <= 0) = []
> take' n [] | (n > 0) = error "take': list too short"
>            | otherwise = []
> take' n (x:xs) = x : take' (n-1) xs
>
> I'm not sure why you'd want that, though.  The standard  
> implementation gracefully handles all inputs, and usually turns out  
> to be what you want.

There are two sides to this form of "grace", though. I'll grant you,  
it's
quite hard to pull off a successful fraud without a degree of aplomb.

I always hope that key invariants and hygiene conditions can be built  
into
the static semantics of programs, but where that's impractical  
somehow, I
prefer if the dynamic behaviour makes it as easy as possible to  
assign the
blame for errors. In such circumstances, I'd like operations to complain
about bogus input, rather than producing bogus output.

These GIGO problems do bite in real life. I spent a long time finding  
a bug
in somebody else's typechecker which boiled down to the silly mistake of
zipping the wrong lists together. The right lists were guaranteed to  
match
in length, but there was no reason for the wrong lists to do so.  
Problem:
unless you were doing fairly wacky stuff, they both happened to have  
length
zero. Once weirder things arrived, the discrepancies showed up and the
truncations started happening, causing well-formed but ill-typed  
expressions
to be generated by and propagated around the kernel of the system, which
eventually choked in some essentially random place. We had many suspects
before we found the culprit. If the programmer had used a version of zip
which bombed in off-diagonal cases, we'd have been straight there.

So I might very well consider having more than one version of take  
around,
depending on my requirements for its use. I might even consider the more
informative function which also returns the length of the shortfall.
In a dependently typed setting, I wouldn't write take and drop: I'd  
equip
lists with a view incorporating both, guaranteeing the length invariants
and that the sublists actually append to the input. But where shame is
unattainable, blame is really quite important.

All the best

Conor

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Is "take" behaving correctly?

haskell-2
Conor McBride wrote:

> Hi folks
>
> On 12 Sep 2007, at 00:38, Brent Yorgey wrote:
>
>>
>> On 9/11/07, PR Stanley <[hidden email]> wrote: Hi
>> take 1000 [1..3] still yields [1,2,3]
>> I thought it was supposed to return an error.
>
> [..]
>
>> If for some reason you want a version that does return an error in
>> that situation, you could do something like the following:
>>
>> take' n _ | (n <= 0) = []
>> take' n [] | (n > 0) = error "take': list too short"
>>            | otherwise = []
>> take' n (x:xs) = x : take' (n-1) xs
>>
>> I'm not sure why you'd want that, though.  The standard implementation
>> gracefully handles all inputs, and usually turns out to be what you want.
>
> There are two sides to this form of "grace", though. I'll grant you, it's
> quite hard to pull off a successful fraud without a degree of aplomb.
>
> I always hope that key invariants and hygiene conditions can be built into
> the static semantics of programs, but where that's impractical somehow, I
> prefer if the dynamic behaviour makes it as easy as possible to assign the
> blame for errors. In such circumstances, I'd like operations to complain
> about bogus input, rather than producing bogus output.
>

Then you want a runtime assertion checking error helpful Data.List replacement.

Could you use Control.Exception.assert and make a wrapper for Data.List?

http://www.haskell.org/ghc/docs/latest/html/users_guide/sec-assertions.html

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Is "take" behaving correctly?

Henning Thielemann
In reply to this post by Conor McBride

On Wed, 12 Sep 2007, Conor McBride wrote:

> Hi folks
>
> On 12 Sep 2007, at 00:38, Brent Yorgey wrote:
>
>> On 9/11/07, PR Stanley <[hidden email]> wrote: Hi
>> take 1000 [1..3] still yields [1,2,3]
>> I thought it was supposed to return an error.
>
> [..]
>
>> If for some reason you want a version that does return an error in that
>> situation, you could do something like the following:
>>
>> take' n _ | (n <= 0) = []
>> take' n [] | (n > 0) = error "take': list too short"
>>           | otherwise = []
>> take' n (x:xs) = x : take' (n-1) xs
>>
>> I'm not sure why you'd want that, though.  The standard implementation
>> gracefully handles all inputs, and usually turns out to be what you want.
>
> I always hope that key invariants and hygiene conditions can be built into
> the static semantics of programs, but where that's impractical somehow, I
> prefer if the dynamic behaviour makes it as easy as possible to assign the
> blame for errors. In such circumstances, I'd like operations to complain
> about bogus input, rather than producing bogus output.

Seconded. The List functions have some kind of "scripting language
semantics" or "C semantics", that is, consume almost every input,
regardless of the meaning of the output, just in order to avoid error
messages. Indeed there are some usages like taking a prefix of an infinite
list (zip "abc" [1..]), where the current behaviour of 'zip' is useful.
However it would be better to have versions of 'zip' to support these
special cases. Ideally the equal length could be expressed in types, like

  zipInfInf :: InfiniteList a -> InfiniteList b -> InfiniteList (a,b)
  zipInf    :: InfiniteList a -> FiniteList n b -> FiniteList n (a,b)
  zip       :: FiniteList n a -> FiniteList n b -> FiniteList n (a,b)  ,

which would need dependent types.

> These GIGO problems do bite in real life. I spent a long time finding a bug
> in somebody else's typechecker which boiled down to the silly mistake of
> zipping the wrong lists together. The right lists were guaranteed to match
> in length, but there was no reason for the wrong lists to do so.

I had a bug which was due to the wrong order of applications of 'filter'
and 'zip'. I had two lists 'a' and 'b' of the same length, where 'b'
contained a condition for filtering, then I wrote
   zip a (filter p b)
  instead of
   filter (p . snd) $ zip a b
  The wrong version was temptingly short, but it matched the wrong
elements. The bug had been catched early, if 'zip' would have checked the
length of its inputs.
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Re: Is "take" behaving correctly?

Conor McBride
In reply to this post by haskell-2
Hi

On 12 Sep 2007, at 11:44, ChrisK wrote:

> Conor McBride wrote:
>> I'd like operations to complain
>> about bogus input, rather than producing bogus output.
>>
>
> Then you want a runtime assertion checking error helpful Data.List  
> replacement.
>
> Could you use Control.Exception.assert and make a wrapper for  
> Data.List?
>
> http://www.haskell.org/ghc/docs/latest/html/users_guide/sec- 
> assertions.html

Hmmm. It might be quite annoying to make it a wrapper if it's just a  
question
of appealing to error rather than returning dummy values in failure  
cases.
Defining the domain of a function can be quite like defining the  
function
itself. Also, sometimes there can be problems arriving at a Bool. For  
example,
zipping colists is a productive coprogram, and it can raise errors in
off-diagonal cases, but you can't compute in advance whether you're  
on the
diagonal.

A more serious point is that in some cases we might want take to
underapproximate, or zip to truncate (or tail [] = [] ?). I don't  
think there's
always a clear "library" choice here. I tend to be pragmatic about  
it. I was
just pointing out that it does sometimes make sense to use less defined
functions when one has a more specific domain in mind. I'm usually  
happy to
write the fussy variants myself, if I'm that agitated.

Funny old world

Conor

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Re: Is "take" behaving correctly?

Neil Mitchell
Hi

> A more serious point is that in some cases we might want take to
> underapproximate, or zip to truncate (or tail [] = [] ?). I don't
> think there's
> always a clear "library" choice here.

I have a zipWithEq function I often use, which crashes if the zip'd
lists aren't equal. I also have tailSafe which does the tailSafe [] =
[] behaviour. I created a hackage package "safe" for the tailSafe
function and others, http://www-users.cs.york.ac.uk/~ndm/safe/ . If
anyone wants to extend that with deliberately unsafe functions, such
as zipWithUnsafe, zipUnsafe, takeUnsafe etc, I'd be happy to accept a
patch. If not, I'll probably do it myself at some point in the
(potentially distant) future.

Thanks

Neil
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Re: Is "take" behaving correctly?

PR Stanley
In reply to this post by Conor McBride
I quite like the argument that take is a total function and as such all its return values are from teh specificed range. I can also see the logic in
take n [] = [] where n > 0
taking n from nothing, or the empty set, returns nothing!
The same should apply to head and tail. head or tail  of [] should be [].

What does the list think?
Cheers, Paul
At 16:43 12/09/2007, you wrote:
Hi

On 12 Sep 2007, at 11:44, ChrisK wrote:

Conor McBride wrote:
I'd like operations to complain
about bogus input, rather than producing bogus output.

Then you want a runtime assertion checking error helpful Data.List 
replacement.

Could you use Control.Exception.assert and make a wrapper for 
Data.List?

http://www.haskell.org/ghc/docs/latest/html/users_guide/sec- assertions.html

Hmmm. It might be quite annoying to make it a wrapper if it's just a 
question
of appealing to error rather than returning dummy values in failure 
cases.
Defining the domain of a function can be quite like defining the 
function
itself. Also, sometimes there can be problems arriving at a Bool. For 
example,
zipping colists is a productive coprogram, and it can raise errors in
off-diagonal cases, but you can't compute in advance whether you're 
on the
diagonal.

A more serious point is that in some cases we might want take to
underapproximate, or zip to truncate (or tail [] = [] ?). I don't 
think there's
always a clear "library" choice here. I tend to be pragmatic about 
it. I was
just pointing out that it does sometimes make sense to use less defined
functions when one has a more specific domain in mind. I'm usually 
happy to
write the fussy variants myself, if I'm that agitated.

Funny old world

Conor

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Re: Is "take" behaving correctly?

Neil Mitchell
Hi

>  The same should apply to head and tail. head or tail  of [] should be [].
>
>  What does the list think?

Disagree, strongly. Its not even possible for head, since [a] -> a.
Wadler's theorems for free states that if head is given an empty list
the _only_ thing it can do is crash.

Thanks

Neil
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
1234