Discrete Probability Distribution Type as a Monad
In this lesson, we will learn about additive monads.
We'll cover the following
Before we get going on this lesson, you might want to refresh your memory of what an additive monad is.
Additive Monad
Briefly, an additive monad is a monad where there is a “zero value”; like the number zero, “multiplying” by zero produces a zero, and “adding” a zero is an identity.
For example, the sequence monad, IEnumerable<T>
, has a zero: the empty sequence. If we Select
or SelectMany
from the empty sequence — our analog of “multiplying” — we get an empty sequence. If we concatenate an empty sequence onto another sequence — the sequence analog of “adding” — we get the original sequence.
All additive monads can have a Where
function defined on them; if we wanted to implement Where
for sequences and didn’t care about performance, we could implement it like this:
public static IEnumerable<T> Single<T>(T t)
{
yield return t;
}
public static IEnumerable<T> Zero<T>()
{
yield break;
}
// Non-standard Where:
public static IEnumerable<T> Where<T>(this IEnumerable<T> items, Func<T, bool> predicate) =>
from a in items
from b in predicate(a) ? Single(a) : Zero<T>()
select b;
That’s slow and produces hideous collection pressure, but it works; our actual implementation of Where
is just an optimization.
What about the converse? Our probability monad IDiscreteDistribution<T>
has a Where
function defined. We have a Singleton<T>
type. But our implementation of the distribution monad does not appear to have a zero value. It seems plausible that there should be a way to express Where
on distributions as we did with the sequence monad: as a SelectMany
that produces either the single or zero distributions based on the predicate.
Give that some thought, and then look at the answer.
Get hands-on with 1200+ tech skills courses.