Bas van Dijk v.dijk.bas at gmail.com
Thu Oct 22 14:15:32 EDT 2009

```On Wed, Oct 21, 2009 at 9:44 PM, Wouter Swierstra <wss at cs.nott.ac.uk> wrote:
> The only change with the previous version has been to add irrefutable
> patterns to several function definitions. This is rather delicate design
> decision: too many irrefutable patterns could result in thunks not being
> evaluated; too few irrefutable patterns could cause your functions diverge.
> As a rule of thumb I've chosen only to use irrefutable patterns in functions
> that produce streams from streams. The operations that observe finite
> information (a prefix, the element at index i, etc.) do not have have
> irrefutable patterns and force evaluation to weak head normal form.

Hi Wouter,

I have two questions:

1) What's the difference between your:
"tail ~(Cons _ xs) = xs"
and the more simple:
"tailStrict (Cons _ xs) = xs" ?

I know they're desugared to:
"tail ys = let Cons _ xs = ys in xs"
and:
"tailStrict ys = case ys of Cons _ xs -> xs" respectively.

But aren't they operationally the same:

"tail undefined = undefined"
and:
"tailStrict undefined = undefined"

2) Why don't you also use an irrefutable pattern in "take"? "take" is
now defined as:

take :: Int -> Stream a  -> [a]
take n (Cons x xs)
| n == 0    = []
| n > 0     =  x : (take (n - 1) xs)
| otherwise = error "Stream.take: negative argument."

so "take 0 undefined = undefined" while:

takeLazy :: Int -> Stream a  -> [a]
takeLazy n ~(Cons x xs)
| n == 0    = []
| n > 0     =  x : (takeLazy (n - 1) xs)
| otherwise = error "Stream.take: negative argument."

"takeLazy 0 undefined = []"

regards,

Bas
```