2

Can we define a recursion scheme (without losing any of their generality) that constructs the value top-down, instead of bottom-up?

This would be quite helpful as I've seen plenty of times where the function, defined internally with a recursion scheme was first applying reverse to its input, clearly signalling the need for a foldl-like "front to back" execution.

Welperooni
  • 633
  • 6
  • 13

1 Answers1

12

Although it's a common belief that cata works "bottom-up", it can actually express many "top-down" constructions, by instantiating the carrier with a function whose parameter is the information being passed "top-down":

cata :: (F  c       ->  c      ) -> Fix F -> c       -- general signature
     :: (F (i -> d) -> (i -> d)) -> Fix F -> i -> d  -- with  c = (i -> d)

That's how you can implement foldl or reverse using foldr (which is cata for lists).

--   foldl :: (b -> a -> b) -> b -> [a] -> b
-- using
--   foldr :: (a -> (b -> b) -> (b -> b)) -> (b -> b) -> [a] -> b -> b

foldl f b xs = foldr (\x go z -> go (f z x)) id xs b

Here's another example to label a tree by depth, counting from the root:

data Tree a = Node (Tree a) a (Tree a) | Leaf

makeBaseFunctor ''Tree  -- recursion-schemes

byDepth :: Tree a -> Tree Integer
byDepth t = cata byDepthF t 0 where
  byDepthF :: TreeF a (Integer -> Tree Integer) -> Integer -> Tree Integer
  byDepthF (NodeF u _ v) !d = Node (u (d + 1)) d (v (d + 1))
  byDepthF LeafF = Leaf
Li-yao Xia
  • 31,896
  • 2
  • 33
  • 56
  • Could you perhaps add an example of such manipulation of `cata`? – Welperooni Sep 03 '19 at 19:12
  • @Welperooni `foldr = cata`, so there already is an example in this answer. – amalloy Sep 03 '19 at 19:47
  • Indeed, `foldr` is `cata`, though I also added another example with trees, hope that helps. – Li-yao Xia Sep 03 '19 at 19:53
  • it's a correct answer, but the problem is that it requires us to remove clarity from a solution that gave us above all a very clear way to express business logic and I hoped we could preserve that. *sigh* – Welperooni Sep 03 '19 at 20:52