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 Tdeğer) ve bunu monad'a "sarar" (yani, bir M<T>değer üretir ). Yana returnC # ayrılmış bir anahtar kelimedir, ben kullanacağız pureşu andan itibaren bu operasyon başvurmak için. C # 'da, pureimzası olan bir yöntem olurdu:
M<T> pure(T v);
bind/ flatmapbir monadik değer ( M<A>) ve bir işlev alır f. fsaf bir değer alır ve monadik bir değer ( M<B>) döndürür . Bunlardan bindyeni bir monadik değer ( M<B>) üretir . bindaşağıdaki C # imzasına sahiptir:
M<B> bind(M<A> mv, Func<A, M<B>> f);
Ayrıca, bir monad olmak pureve 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:
puresaf bir değeri işleve sarar. Bu purebir monad için benzerdir . Aslında, aynı zamanda bir monad olan functors için, ikisi aynı olmalıdır.
fmapgiriş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, Monadbiraz 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 joinve her ikisinin joinve 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 IObservableve 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 IObservableolduğumuza göre, bu işleçten ücretsiz bir monad oluşturabiliriz. IObservableSerbest 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 .