I was reading http://www.haskellforall.com/2013/06/from-zero-to-cooperative-threads-in-33.html where an abstract syntax tree is derived as the free monad of a functor repres
There is a deep and 'simple' connection.
It's a consequence of adjoint functor theorem, left adjoints preserve initial objects: L 0 ≅ 0
.
Categorically, Free f
is a functor from a category to its F-algebras (Free f
is left adjoint to a forgetful functor going the other way 'round). Working in Hask our initial algebra is Void
Free f Void ≅ 0
and the initial algebra in the category of F-algebras is Fix f
: Free f Void ≅ Fix f
import Data.Void
import Control.Monad.Free
free2fix :: Functor f => Free f Void -> Fix f
free2fix (Pure void) = absurd void
free2fix (Free body) = Fix (free2fix <$> body)
fixToFree :: Functor f => Fix f -> Free f Void
fixToFree (Fix body) = Free (fixToFree <$> body)
Similarly, right adjoints (Cofree f
, a functor from Hask to the category of F-coalgebras) preserves final objects: R 1 ≅ 1
.
In Hask this is unit: ()
and the final object of F-coalgebras is also Fix f
(they coincide in Hask) so we get: Cofree f () ≅ Fix f
import Control.Comonad.Cofree
cofree2fix :: Functor f => Cofree f () -> Fix f
cofree2fix (() :< body) = Fix (cofree2fix <$> body)
fixToCofree :: Functor f => Fix f -> Cofree f ()
fixToCofree (Fix body) = () :< (fixToCofree <$> body)
Just look how similar the definitions are!
newtype Fix f
= Fix (f (Fix f))
Fix f
is Free f
with no variables.
data Free f a
= Pure a
| Free (f (Free f a))
Fix f
is Cofree f
with dummy values.
data Cofree f a
= a <: f (Cofree f a)