I am trying to understand how this very abstract recursive function from the Haskell recursion-schemes
package works (or, indeed, what it does!) - from this file:
class Functor (Base t) => Corecursive t where
[...]
-- | A generalized postpromorphism
gpostpro
:: (Recursive t, Monad m)
=> (forall b. m (Base t b) -> Base t (m b)) -- distributive law
-> (forall c. Base t c -> Base t c) -- natural transformation
-> (a -> Base t (m a)) -- a (Base t)-m-coalgebra
-> a -- seed
-> t
gpostpro k e g = a . return where a = embed . fmap (ana (e . project) . a . join) . k . liftM g
In particular, what I want to understand is: how does it apply the g
function which mentions the monad type constructor m
, but then return a value of the t
type, which doesn't mention or depend on m
? I thought escaping from arbitrary monads was impossible in Haskell!
I first loaded the source file into Intero to try to use its type-at-point feature, but that attempt failed.
I then loaded it into GHCi using cabal repl
, and tried to follow the types through the composed functions one at a time, using GHCi to help with type inference, by commenting out various bits of the definition. However, when I got to the fmap
, I couldn't work out what to comment out, because if I uncommented the recursive a
invocation but commented out other stuff, I thought it probably wouldn't even compile because the partially-commented-out definition of a
wouldn't have the right type.