Various recursion scheme boil down to specific instantiation of refold
refold :: Functor s => (s b -> b) -> (a -> s a) -> a -> b
refold f g = go where go a = f (fmap go (g a))
What is the meaningful interpretation of refold ?
The data type data Nu f = forall a. Nu (a -> f a) a and newtype Mu f = Mu {unMu :: forall b. (f b -> b) -> b} can be seen as the colimit and limit of the forget functor from coalgebras and algebras, and refold is a morphism between those, but does it shed light on refold ?
refold' :: forall s. Functor s => Nu s -> Mu s
refold' (Nu g (a :: a)) = Mu mu where
mu :: forall b. (s b -> b) -> b
mu f = go a where
go :: a -> b
go a = f (fmap go (g a))
I guess it depends what you mean by "meaningful interpretation".
If
sis a base functor for a recursive data type and a corecursive codata type, like the following functors ~ ListF efor the recursive list data type[e](which, in Haskell, is also a corecursive stream codata type):then an
s-coalgebra of typea -> s atogether with a starting seedacan generate a value of codata type[e]by unfolding from that seed, while ans-algebra of types b -> bcan consume a value of data type[e]by folding into a value of typeb. Therefoldfunction just combines the operation of unfolding fromaand folding intob, without actually creating an intermediate codata/data type.For example, you can generate the (finite) codata stream
[10,9..1]by unfolding from anIntegerseed using the starting value / coalgebra pair(a,g)as follows:and fold a list to calculate its
Intlength using the algebra:The
refoldfunction just combines these operations:In this particular case, it calculates the length
10of the stream/list[1..10]without actually creating any intermediate stream/list.I guess the intuition is that if an operation can be imagined as an F-recursion applied to an F-corecursion for the same functor F, then it's a
refold. Or, maybe more practically, if an algorithm has an internal recursive structure that matches the functor F, it can be expressed as arefold. The documentation forrefoldinrecursion-schemesgives the example of quicksort having a recursive structure that matches a binary tree, though you've presumably already seen that example.Note: What follows is wrong or at best imprecise, but I'll try to think a little more about it.
In practice,refoldisn't only used as a morphism between universal data types, but if you have a final s-coalgebra for a codata typeCassociated with the functors:and an initial s-algebra for a data type
Dalso associated with the functors:then
refold makeD eatCshould be a natural morphism from codata typeCto data typeD. That is, it should be the unique morphism satsifying:I'm not sure that aspect is tremendously interesting...