Reputation: 16841
I'm working through exercises in Graham Hutton's book "Programming in Haskell" and as part of one exercise I've re-implemented Haskell's last
function like so:
lasst xs = drop (length xs - 1) xs
Now this works nicely for a non-empty list:
> lasst [1,2,3,4,5]
[5]
But, surprisingly to me, for an empty list it returns an empty list:
> lasst []
[]
I'm surprised by this because I would expect (length []) - 1
to be evaluated into -1
and the subsequent evaluation of drop -1 []
to throw.
Why does my implementation return an empty list for an empty list, rather than throw an exception?
Upvotes: 1
Views: 166
Reputation: 116174
drop
and take
are total functions: they always return something without causing a runtime error, no matter what the (total) arguments are. Their definition makes it so that
take k xs ++ drop k xs == xs
holds for every k
and (finite) xs
. Note that k
can be negative, or even larger than the length of xs
, and the above is still guaranteed.
It might be surprising at first, but they have the following behavior. Assume xs = [1,2,3]
. Then
k take drop
==========================
...
-2 [] [1,2,3]
-1 [] [1,2,3]
0 [] [1,2,3]
1 [1] [2,3]
2 [1,2] [3]
3 [1,2,3] []
4 [1,2,3] []
5 [1,2,3] []
...
Personally, I'm unsure about whether their totality is a good idea. It would make sense for them to cause a runtime error for negative k
, or for k
larger than the length. Still, that's what Haskell does.
(Note in passing that tail xs
and drop 1 xs
differ when xs=[]
, because tail
is not total.)
Upvotes: 2
Reputation: 477437
The Haskell report '10 specifies the the standard Prelude. In this section, we see:
drop :: Int -> [a] -> [a] drop n xs | n <= 0 = xs drop _ [] = [] drop n (_:xs) = drop (n-1) xs
So for a negative n
, it will return the entire list. This makes sense with respect to the documentation of drop
:
drop n xs
returns the suffix ofxs
after the firstn
elements, or[]
ifn > length xs
.
So the first -1
elements of a list, are no elements at all.
This is further covered in one of the examples of drop
:
drop (-1) [1,2] == [1,2]
Upvotes: 4