I was looking through the recursion-schemes
package documentation a few days ago, and was struck by the type signature of (co)elgot
.
elgot :: Functor f => (f a -> a) -> (b -> Either a (f b)) -> b -> a
coelgot :: Functor f => ((a, f b) -> b) -> (a -> f a) -> a -> b
In particular, we can rewrite the coelgot
signature as
coelgot :: Functor f => (a -> f a, (a, f b) -> b) -> (a -> b)
It takes a lens to a function!
The a -> f a
is the “getter” and (a, f b) -> b
is our “setter”.
Dually, we have elgot
taking a prism to a function.
elgot :: Functor f => (b -> Either a (f b), f a -> a) -> (b -> a)
Let’s look at the implementation for elgot
, with the arguments renamed to align with our lensy interpretation.
coelgot set get = h
where h = set . (id &&& fmap h . get)
If you squint at the recursive equation, you can see that it is h = over (fmap h)
.
The same is true of elgot
.
We can rewrite both in a very profunctor optics way as follows.
elgot :: Functor f
=> (forall p. Choice p => p (f a) (f b) -> p a b)
-> (a -> b)
elgot prism = soln where soln = prism (fmap soln)
coelgot :: Functor f
=> (forall p. Strong p => p (f a) (f b) -> p a b)
-> (a -> b)
coelgot lens = soln where soln = lens (fmap soln)
So, these optics are specifying a recursive equation.
What happens if we use a different kind of optic?
Swapping out Strong
/Choice
for Traversing
would produce
a way of taking traversals to functions.
Would that be useful?
We can even go a bit further and not restrict ourselves to functions.
For some profunctor constrant C
, we could have
opticRecSol
:: (Functor f, Mapping p)
=> (forall q. (Mapping q, C q) => q (f a) (f b) -> q a b)
-> p a b
opticRecSol optic = soln
where soln = optic (map' soln)
How many different recursion schemes are just a special case of the above? Of course we shouldn’t get too carried away, we can write down recursive equations like that, but they may or may not have a meaningful solution.
I’m sure I’m not the first to notice this connection between (co)elgot
and lenses/prisms, but I’ve never seen it mentioned and I’d love to see how far this idea can be pushed.