I've recently looked up some guides on recursion schemes in Haskell, however most articles don't go much beyond implementing the basic infrastructure required for these concepts.
Given a recursive data type like a binary tree
data Tree a =
Leaf a
| Node a (Tree a) (Tree a)
we would also implement a similar structure which replaces the recursive parts of the definition with a type parameter, in order to be able to use generic folds like cata
and ana
and so on
data TreeF a r =
LeafF a
| NodeF a r r
along with a fix point combinator
newtype Fix f = In { out :: f (Fix f) }
which allows us to express an arbitrarily nested tree with our new representation.
So my question is quite straight forward (and maybe stupid): Which representation of the data structure do we actually use in the rest of our program? Do we need both? Theoretically we could use TreeF
only, however from what I found when playing around with an expression grammar tree that was implemented this way, that tends to be a little problematic, mainly since you now have to wrap each level of the tree in the new data constructor and as far as I noticed you can no longer automatically derive from the basic typeclasses like Show
or Eq
.