单子
一个单子组成
此外,要成为一个单子,pure
并且bind
必须遵守三个单子法。
现在,在C#中建模monad的一种方法是构造一个接口:
interface Monad<M> {
M<T> pure(T v);
M<B> bind(M<A> mv, Func<A, M<B>> f);
}
(注意:为了使内容简洁明了,我将在此答案中放一些代码的自由。)
现在,我们可以通过实现的具体实现来实现用于具体数据类型的monad Monad<M>
。例如,我们可以实现以下monad IEnumerable
:
class IEnumerableM implements Monad<IEnumerable> {
IEnumerable<T> pure(T v) {
return (new List<T>(){v}).AsReadOnly();
}
IEnumerable<B> bind(IEnumerable<A> mv, Func<A, IEnumerable<B>> f) {
;; equivalent to mv.SelectMany(f)
return (from a in mv
from b in f(a)
select b);
}
}
(我故意使用LINQ语法来调出LINQ语法和monad之间的关系。但是请注意,我们可以用调用代替LINQ查询SelectMany
。)
现在,我们可以定义一个单子IObservable
吗?看起来是这样的:
class IObservableM implements Monad<IObservable> {
IObservable<T> pure(T v){
Observable.Return(v);
}
IObservable<B> bind(IObservable<A> mv, Func<A, IObservable<B>> f){
mv.SelectMany(f);
}
}
为了确保我们有一个单子,我们需要证明单子法则。这可能很简单(而且我对Rx.NET不够熟悉,无法知道是否仅从规范中就可以证明它们),但这是一个充满希望的起点。为了便于讨论的其余部分,让我们假设在这种情况下适用单子法则。
免费单子
没有单数的“自由单子”。相反,自由单子是由函子构造的一类单子。也就是说,给定函子F
,我们可以自动派生一个monad F
(即的自由monad F
)。
函子
像单子一样,函子可以由以下三个项定义:
- 在单个无限制类型变量上参数化的数据类型。
两种操作:
pure
将纯值包装到函子中。这类似于pure
单子。实际上,对于也是单子的函子,两者应该是相同的。
fmap
通过给定函数将输入中的值映射到输出中的新值。它的签名是:
F<B> fmap(Func<A, B> f, F<A> fv)
像单子一样,函子必须遵守函子定律。
与单子类似,我们可以通过以下接口对函子进行建模:
interface Functor<F> {
F<T> pure(T v);
F<B> fmap(Func<A, B> f, F<A> fv);
}
现在,由于monad是函子的子类,我们还可以重构Monad
一下:
interface Monad<M> extends Functor<M> {
M<T> join(M<M<T>> mmv) {
Func<T, T> identity = (x => x);
return mmv.bind(x => x); // identity function
}
M<B> bind(M<A> mv, Func<A, M<B>> f) {
join(fmap(f, mv));
}
}
在这里,我添加了其他方法join
,并提供了join
和的默认实现bind
。但是请注意,这些是循环定义。因此,您必须至少覆盖一个或另一个。另外,请注意,该pure
继承自Functor
。
IObservable
和免费的Monad
现在,由于我们已经定义了monad IObservable
并且monad是函子的子类,因此,我们必须能够为定义函子实例IObservable
。这是一个定义:
class IObservableF implements Functor<IObservable> {
IObservable<T> pure(T v) {
return Observable.Return(v);
}
IObservable<B> fmap(Func<A, B> f, IObservable<A> fv){
return fv.Select(f);
}
}
现在我们为定义了函子IObservable
,我们可以从该函子构造一个免费的monad。这正是IObservable
与自由monad的关系,即我们可以从构造一个自由monad IObservable
。
Cont
我所见过的唯一一个单声道建议不能通过免费单声道表示的那样,人们可能会认为FRP可以表示。正如几乎任何东西。