<div dir="auto">The fragility of this feature remains frustrating. A few days ago, I wrote this code for building a complete binary tree from its breadth-first traversal. (This is an improvement of a version by Will Ness.)<div dir="auto"><br></div><div dir="auto"><div dir="auto">data Tree a</div><div dir="auto">  = Empty</div><div dir="auto">  | Node a (Tree a) (Tree a)</div><div dir="auto">  deriving Show</div><div dir="auto"><br></div><div dir="auto">-- An infinite list</div><div dir="auto">data IL a = a :< IL a<br></div><div dir="auto">infixr 5 :<</div><div dir="auto"><br></div><div dir="auto"><div dir="auto">bft :: [a] -> Tree a</div><div dir="auto">bft xs = tree</div><div dir="auto">  where</div><div dir="auto">    tree :< subtrees = go xs subtrees</div><div dir="auto"><br></div><div dir="auto">    go :: [a] -> IL (Tree a) -> IL (Tree a)</div><div dir="auto">    go (a : as) ~(b1 :< ~(b2 :< bs)) = Node a b1 b2 :< go as bs</div><div dir="auto">    go [] _ = fix (Empty :<)</div><div dir="auto"><br></div><div dir="auto">When GHC compiles the lazy patterns, we get something essentially like this:</div><div dir="auto"><br></div><div dir="auto">    go (a : as) ys =</div><div dir="auto">      Node a</div><div dir="auto">        (case ys of b1 :< _ -> b1)</div><div dir="auto">        (case ys of _ :< b2 :< _ -> b2)</div><div dir="auto">      :<</div><div dir="auto">      go as (case ys of _ :< _ :< bs -> bs)</div><div dir="auto"><br></div><div dir="auto">Now `<span style="font-family:sans-serif">case ys of b1 :< _ -> b1` is a selector thunk, which is cool. The GC can reduce it as soon as either of the other thunks is forced. But neither of the other two case expressions is a selector thunk, so neither will ever be reduced by the GC. If I consume the result tree using an inorder traversal, for example, then all the elements in the left subtree of the root will remain live until I start to consume the right subtree of the root.</span></div><div dir="auto"><br></div><div dir="auto">I can instead write this:</div><div dir="auto"><br></div><div dir="auto"><div dir="auto" style="font-family:sans-serif">   go (a : as) ys = Node a b1 b2 :< go as bs</div><div dir="auto" style="font-family:sans-serif">      where</div><div dir="auto" style="font-family:sans-serif">         {-# NOINLINE b2bs #-}</div><div dir="auto" style="font-family:sans-serif">         b1 :< b2bs = ys</div><div dir="auto" style="font-family:sans-serif">         b2 :< bs = b2bs</div><div dir="auto" style="font-family:sans-serif"><br></div><div dir="auto" style="font-family:sans-serif">Now all the suspended selections are selector thunks, so things should clean up nicely. There are still three problems, though. The first is that this is harder to read. The second is that now we have four suspended selections instead of three. Finally, if b1 is not the first one forced, we'll need to force two thunks instead of one.</div><div dir="auto" style="font-family:sans-serif"><br></div><div dir="auto" style="font-family:sans-serif">Can't we do any better?</div></div></div></div></div>