I've seen the term Free Monad pop up every now and then for some time, but everyone just seems to use/discuss them without giving an explanation of what they are. So: what are free monads? (I'd say I'm familiar with monads and the Haskell basics, but have only a very rough knowledge of category theory.)
相关问题
- Understanding do notation for simple Reader monad:
- Making Custom Instances of PersistBackend
- Haskell: What is the differrence between `Num [a]
- applying a list to an entered function to check fo
- Haskell split a list into two by a pivot value
相关文章
- Is it possible to write pattern-matched functions
- Haskell underscore vs. explicit variable
- Top-level expression evaluation at compile time
- Stuck in the State Monad
- foldr vs foldr1 usage in Haskell
- List of checkboxes with digestive-functors
- How does this list comprehension over the inits of
- Replacing => in place of -> in function type signa
The Free Monad (data structure) is to the Monad (class) like the List (data structure) to the Monoid (class): It is the trivial implementation, where you can decide afterwards how the content will be combined.
You probably know what a Monad is and that each Monad needs a specific (Monad-law abiding) implementation of either
fmap
+join
+return
orbind
+return
.Let us assume you have a Functor (an implementation of
fmap
) but the rest depends on values and choices made at run-time, which means that you want to be able to use the Monad properties but want to choose the Monad-functions afterwards.That can be done using the Free Monad (data structure), which wraps the Functor (type) in such a way so that the
join
is rather a stacking of those functors than a reduction.The real
return
andjoin
you want to use, can now be given as parameters to the reduction functionfoldFree
:To explain the types, we can replace
Functor f
withMonad m
andb
with(m a)
:A Haskell free monad is a list of functors. Compare:
Pure
is analogous toNil
andFree
is analogous toCons
. A free monad stores a list of functors instead of a list of values. Technically, you could implement free monads using a different data type, but any implementation should be isomorphic to the above one.You use free monads whenever you need an abstract syntax tree. The base functor of the free monad is the shape of each step of the syntax tree.
My post, which somebody already linked, gives several examples of how to build abstract syntax trees with free monads
Here's an even simpler answer: A Monad is something that "computes" when monadic context is collapsed by
join :: m (m a) -> m a
(recalling that>>=
can be defined asx >>= y = join (fmap y x)
). This is how Monads carry context through a sequential chain of computations: because at each point in the series, the context from the previous call is collapsed with the next.A free monad satisfies all the Monad laws, but does not do any collapsing (i.e., computation). It just builds up a nested series of contexts. The user who creates such a free monadic value is responsible for doing something with those nested contexts, so that the meaning of such a composition can be deferred until after the monadic value has been created.
Edward Kmett's answer is obviously great. But, it is a bit technical. Here is a perhaps more accessible explanation.
Free monads are just a general way of turning functors into monads. That is, given any functor
f
Free f
is a monad. This would not be very useful, except you get a pair of functionsthe first of these lets you "get into" your monad, and the second one gives you a way to "get out" of it.
More generally, if X is a Y with some extra stuff P, then a "free X" is a a way of getting from a Y to an X without gaining anything extra.
Examples: a monoid (X) is a set (Y) with extra structure (P) that basically says it has an operation (you can think of addition) and some identity (like zero).
So
Now, we all know lists
Well, given any type
t
we know that[t]
is a monoidand so lists are the "free monoid" over sets (or in Haskell types).
Okay, so free monads are the same idea. We take a functor, and give back a monad. In fact, since monads can be seen as monoids in the category of endofunctors, the definition of a list
looks a lot like the definition of free monads
and the
Monad
instance has a similarity to theMonoid
instance for listsnow, we get our two operations
I think a simple concrete example will help. Suppose we have a functor
with the obvious
fmap
. ThenFree F a
is the type of trees whose leaves have typea
and whose nodes are tagged withOne
,Two
,Two'
andThree
.One
-nodes have one child,Two
- andTwo'
-nodes have two children andThree
-nodes have three and are also tagged with anInt
.Free F
is a monad.return
mapsx
to the tree that is just a leaf with valuex
.t >>= f
looks at each of the leaves and replaces them with trees. When the leaf has valuey
it replaces that leaf with the treef y
.A diagram makes this clearer, but I don't have the facilities for easily drawing one!
A free foo happens to be the simplest thing that satisfies all of the 'foo' laws. That is to say it satisfies exactly the laws necessary to be a foo and nothing extra.
A forgetful functor is one that "forgets" part of the structure as it goes from one category to another.
Given functors
F : D -> C
, andG : C -> D
, we sayF -| G
,F
is left adjoint toG
, orG
is right adjoint toF
whenever forall a, b:F a -> b
is isomorphic toa -> G b
, where the arrows come from the appropriate categories.Formally, a free functor is left adjoint to a forgetful functor.
The Free Monoid
Let us start with a simpler example, the free monoid.
Take a monoid, which is defined by some carrier set
T
, a binary function to mash a pair of elements togetherf :: T → T → T
, and aunit :: T
, such that you have an associative law, and an identity law:f(unit,x) = x = f(x,unit)
.You can make a functor
U
from the category of monoids (where arrows are monoid homomorphisms, that is, they ensure they mapunit
tounit
on the other monoid, and that you can compose before or after mapping to the other monoid without changing meaning) to the category of sets (where arrows are just function arrows) that 'forgets' about the operation andunit
, and just gives you the carrier set.Then, you can define a functor
F
from the category of sets back to the category of monoids that is left adjoint to this functor. That functor is the functor that maps a seta
to the monoid[a]
, whereunit = []
, andmappend = (++)
.So to review our example so far, in pseudo-Haskell:
Then to show
F
is free, we need to demonstrate that it is left adjoint toU
, a forgetful functor, that is, as we mentioned above, we need to show thatF a → b
is isomorphic toa → U b
now, remember the target of
F
is in the categoryMon
of monoids, where arrows are monoid homomorphisms, so we need a to show that a monoid homomorphism from[a] → b
can be described precisely by a function froma → b
.In Haskell, we call the side of this that lives in
Set
(er,Hask
, the category of Haskell types that we pretend is Set), justfoldMap
, which when specialized fromData.Foldable
to Lists has typeMonoid m => (a → m) → [a] → m
.There are consequences that follow from this being an adjunction. Notably that if you forget then build up with free, then forget again, its just like you forgot once, and we can use this to build up the monadic join. since
UFUF
~U(FUF)
~UF
, and we can pass in the identity monoid homomorphism from[a]
to[a]
through the isomorphism that defines our adjunction,get that a list isomorphism from[a] → [a]
is a function of typea -> [a]
, and this is just return for lists.You can compose all of this more directly by describing a list in these terms with:
The Free Monad
So what is a Free Monad?
Well, we do the same thing we did before, we start with a forgetful functor U from the category of monads where arrows are monad homomorphisms to a category of endofunctors where the arrows are natural transformations, and we look for a functor that is left adjoint to that.
So, how does this relate to the notion of a free monad as it is usually used?
Knowing that something is a free monad,
Free f
, tells you that giving a monad homomorphism fromFree f -> m
, is the same thing (isomorphic to) as giving a natural transformation (a functor homomorphism) fromf -> m
. RememberF a -> b
must be isomorphic toa -> U b
for F to be left adjoint to U. U here mapped monads to functors.F is at least isomorphic to the
Free
type I use in myfree
package on hackage.We could also construct it in tighter analogy to the code above for the free list, by defining
Cofree Comonads
We can construct something similar, by looking at the right adjoint to a forgetful functor assuming it exists. A cofree functor is simply /right adjoint/ to a forgetful functor, and by symmetry, knowing something is a cofree comonad is the same as knowing that giving a comonad homomorphism from
w -> Cofree f
is the same thing as giving a natural transformation fromw -> f
.