2

Half way down here...

https://en.wikibooks.org/wiki/Haskell/Laziness

...is an exercise asking about the effects of changes to an alternative implementation of the head function that uses irrefutable patterns. It provides a definition of head' as follows, noting that it will always return undefined due to irrefutable matching of the first equation:

head' :: [a] -> a
head' ~[]     = undefined
head' ~(x:xs) = x

Then it asks:

  • Why won't changing the order of the equations to head' help here?
  • If the first equation is changed to use an ordinary refutable pattern, will the behavior of head' still be different from that of head? If so, how?

In GHC 7.8.4 it seems that changing the order "helps" at least to the extent of making this function behave like the regular partial version of head, albeit with a different exception in the empty list case. The answer to the second question would appear to me to be "no", but given the "if so, how" addendum, it feels like I must be missing something here too. Can anyone enlighten me? The solutions link on the page does not cover this exercise unfortunately.

Cactus
  • 27,075
  • 9
  • 69
  • 149
Mike Nunan
  • 429
  • 4
  • 8

1 Answers1

7

I'm not sure what the wikibook means by "help". You are correct that changing the order will make it behave essentially like the normal head. Similarly, you are correct that making the first pattern refutable would also make it behave like head. I'm going to say that these questions are confused; they are definitely confusing.

We can verify these answers by calculation (including calculation with GHC):

head [] = ⊥
head (x:xs) = x
head ⊥ = ⊥

head' [] = ⊥
head' (x:xs) = ⊥
head' ⊥ = ⊥

head1 [] = ⊥
head1 (x:xs) = x
head1 ⊥ = ⊥

head2 [] = ⊥
head2 (x:xs) = x
head2 ⊥ = ⊥

head is the standard library version. head' is the version from the wikibook. head1 is the version with the clauses swapped. head2 is the version with the first pattern being a refutable match against []. ⊥ is read as "bottom" and represents a non-terminating or exceptional computation, i.e. undefined.

What I would've expected is examples like the following where there are subtle but significant differences between refutable and irrefutable patterns:

konst ~() = ()

konst' () = ()

partialId ~(x:xs) = x:xs

partialId' (x:xs) = x:xs
Derek Elkins left SE
  • 2,079
  • 12
  • 14
  • With belated thanks for your helpful answer and apologies for any other breaches of etiquette in returning here over 2 years later, I've been looking again at the final part of your answer and am at a loss to find any way of obtaining a different result from partialId versus partialId' for any input I can think of. Would you be able to point out the difference to me please? (I see the difference between the two konst variants clearly enough.) – Mike Nunan Mar 06 '18 at 15:58