I guess it depends what you mean by "meaningful interpretation".
If s
is a base functor for a recursive data type and a corecursive codata type, like the following functor s ~ ListF e
for the recursive list data type [e]
(which, in Haskell, is also a corecursive stream codata type):
{-# LANGUAGE DeriveFunctor #-}
data ListF e b = Nil | Cons e b deriving (Show, Functor)
then an s
-coalgebra of type a -> s a
together with a starting seed a
can generate a value of codata type [e]
by unfolding from that seed, while an s
-algebra of type s b -> b
can consume a value of data type [e]
by folding into a value of type b
. The refold
function just combines the operation of unfolding from a
and folding into b
, without actually creating an intermediate codata/data type.
For example, you can generate the (finite) codata stream [10,9..1]
by unfolding from an Integer
seed using the starting value / coalgebra pair (a,g)
as follows:
a :: Integer
a = 10
g :: Integer -> (ListF Integer) Integer
g 0 = Nil
g n = Cons n (n-1)
and fold a list to calculate its Int
length using the algebra:
f :: (ListF Integer) Int -> Int
f Nil = 0
f (Cons _ b) = 1 + b
The refold
function just combines these operations:
main = print $ refold f g a
In this particular case, it calculates the length 10
of 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 a refold
. The documentation for refold
in recursion-schemes
gives 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, refold
isn't only used as a morphism between universal data types, but if you have a final s-coalgebra for a codata type C
associated with the functor s
:
eatC :: C -> ListF Integer C
and an initial s-algebra for a data type D
also associated with the functor s
:
makeD :: ListF Integer D -> D
then refold makeD eatC
should be a natural morphism from codata type C
to data type D
. That is, it should be the unique morphism satsifying:
fmap h . refold makeD eatC = refold makeD eatC . fmap h
I'm not sure that aspect is tremendously interesting...
f a = Either () a
. NowMu f
is the type of (finite) natural numbers, whileNu f
also adds an "infinity" value to naturals. Yet, we have isosisoNu :: f (Nu f) -> Nu f
andisoMu :: Mu f -> f (Mu f)
, which give usrefold isoNu isoMu :: Nu f -> Mu f
. I believe this has to diverge on the "infinity" value. – Toilette