monads
Bir monad şunlardan oluşur:
Bir endofunctor . Yazılım mühendisliği dünyamızda, bunun tek, sınırsız tip parametresine sahip bir veri tipine karşılık geldiğini söyleyebiliriz. C # 'da, bu formun bir şey olacaktır:
class M<T> { ... }
Bu veri türü üzerinde tanımlanan iki işlem:
return
/ pure
"saf" bir değer alır (yani bir T
değer) ve bunu monad'a "sarar" (yani, bir M<T>
değer üretir ). Yana return
C # ayrılmış bir anahtar kelimedir, ben kullanacağız pure
şu andan itibaren bu operasyon başvurmak için. C # 'da, pure
imzası olan bir yöntem olurdu:
M<T> pure(T v);
bind
/ flatmap
bir monadik değer ( M<A>
) ve bir işlev alır f
. f
saf bir değer alır ve monadik bir değer ( M<B>
) döndürür . Bunlardan bind
yeni bir monadik değer ( M<B>
) üretir . bind
aşağıdaki C # imzasına sahiptir:
M<B> bind(M<A> mv, Func<A, M<B>> f);
Ayrıca, bir monad olmak pure
ve bind
üç monad yasalarına uymak zorundadır.
Şimdi, C # 'daki monadları modellemenin bir yolu bir arayüz oluşturmak olacaktır:
interface Monad<M> {
M<T> pure(T v);
M<B> bind(M<A> mv, Func<A, M<B>> f);
}
(Not: İşleri kısa ve etkileyici tutmak için, bu yanıt boyunca kodla ilgili bazı özgürlükler alacağım.)
Şimdi somut veri türleri için monad uygulayabiliriz Monad<M>
. Örneğin, aşağıdaki monad'ı aşağıdakiler için uygulayabiliriz 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);
}
}
(Kasıtlı olarak LINQ sözdizimi ve monads arasındaki ilişkiyi çağırmak için LINQ sözdizimini kullanıyorum. Ancak LINQ sorgusunu bir çağrı ile değiştirebileceğimizi unutmayın SelectMany
.)
Şimdi, bir monad tanımlayabilir miyiz IObservable
? Öyle görünüyor:
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);
}
}
Bir monadımız olduğundan emin olmak için, monad yasalarını kanıtlamamız gerekir. Bu önemsiz olmayabilir (ve yalnızca spesifikasyondan kanıtlanıp kanıtlanamayacaklarını bilmek için Rx.NET'e yeterince aşina değilim), ancak umut verici bir başlangıç. Bu tartışmanın geri kalanını kolaylaştırmak için, sadece bu durumda monad yasalarının geçerli olduğunu varsayalım.
Ücretsiz Monads
Tekil "serbest monad" yoktur. Daha ziyade, serbest monadlar functorlardan inşa edilen bir monad sınıfıdır. Yani, bir functor verildiğinde F
, otomatik olarak bir monad F
(yani serbest monad F
) türetebiliriz .
functors
Monadlar gibi, functors aşağıdaki üç öğe ile tanımlanabilir:
- Kısıtlanmamış tek bir değişken üzerinde parametreleştirilmiş bir veri türü.
İki işlem:
pure
saf bir değeri işleve sarar. Bu pure
bir monad için benzerdir . Aslında, aynı zamanda bir monad olan functors için, ikisi aynı olmalıdır.
fmap
girişteki değerleri, verilen bir işlev aracılığıyla çıkıştaki yeni değerlerle eşleştirir. İmzası:
F<B> fmap(Func<A, B> f, F<A> fv)
Monadlar gibi, functorların da functor yasalarına uymaları gerekir.
Monad'lara benzer şekilde, functors'ı aşağıdaki arayüz üzerinden modelleyebiliriz:
interface Functor<F> {
F<T> pure(T v);
F<B> fmap(Func<A, B> f, F<A> fv);
}
Şimdi, monadlar functorların bir alt sınıfı olduğu için, Monad
biraz da yeniden düzenleyebiliriz :
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));
}
}
Burada ek bir yöntem ekledim join
ve her ikisinin join
ve varsayılan uygulamalarını sağladım bind
. Ancak bunların dairesel tanımlamalar olduğuna dikkat edin. Bu yüzden en az birini veya diğerini geçersiz kılmanız gerekir. Ayrıca, pure
şimdi miras alındığını unutmayın Functor
.
IObservable
ve Özgür Monadlar
Şimdi, bir monad tanımladığımız için IObservable
ve monadlar bir functor alt sınıfı olduğundan, bunun için bir functor örneği tanımlayabilmemiz gerekir IObservable
. İşte bir tanım:
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);
}
}
Şimdi için tanımlanmış bir işleve sahip IObservable
olduğumuza göre, bu işleçten ücretsiz bir monad oluşturabiliriz. IObservable
Serbest monadlarla tam olarak bu şekilde ilişkilidir - yani, ücretsiz bir monad inşa edebiliriz IObservable
.
Cont
Özgür monad ile ifade edilemediğini önerdiğim tek monad olduğu gibi , muhtemelen FRP'nin olabileceğini varsayabiliriz. As can başka hemen hemen her şey .