Search code examples
haskellrecursionpattern-matchinglazy-evaluationfold

Strictness of pattern matching vs. deconstructing


I'm trying to define primitive recursion in term of foldr, as explained in A tutorial on the universality and expressiveness on fold chapter 4.1.

Here is first attempt at it

simpleRecursive f v xs = fst $ foldr g (v,[]) xs
  where 
    g x (acc, xs) = (f x xs acc,x:xs)

However, above definition does not halt for head $ simpleRecursive (\x xs acc -> x:xs) [] [1..]

Below is definition that halt

simpleRecursive f v xs = fst $ foldr g (v,[]) xs
  where 
    g x r = let (acc,xs) = r
            in (f x xs acc,x:xs)

Given almost similar definition but different result, why does it differ? Does it have to do with how Haskell pattern match?


Solution

  • The crucial difference between the two functions is that in

    g x r = let (acc, xs) = r
            in (f x xs acc, x:xs)
    

    The pattern match on the tuple constructor is irrefutable, whereas in

    g x (acc, xs) = (f x xs acc, x:xs)
    

    it is not. In other words, the first definition of g is equivalent to

    g x ~(acc, xs) = (f x xs acc, x:xs)