monads
monadประกอบด้วย
นอกจากนี้ยังจะเป็น monad pure
และbind
จะต้องปฏิบัติตามกฎหมายทั้งสาม monad
ตอนนี้วิธีหนึ่งในการสร้างแบบจำลอง monads ใน C # คือการสร้างส่วนต่อประสาน:
interface Monad<M> {
M<T> pure(T v);
M<B> bind(M<A> mv, Func<A, M<B>> f);
}
(หมายเหตุ: เพื่อให้สิ่งต่าง ๆ สั้นและแสดงออกฉันจะเอาเสรีภาพพร้อมรหัสในคำตอบนี้)
ตอนนี้เราสามารถสร้าง monads สำหรับ datagypes ที่เป็นรูปธรรม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 และ monads แต่โปรดทราบว่าเราสามารถแทนที่แบบสอบถาม LINQ ด้วยการเรียกไปยังSelectMany
)
ตอนนี้เราสามารถกำหนด monad ให้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);
}
}
เพื่อให้แน่ใจว่าเรามี monad เราต้องพิสูจน์กฎหมาย monad สิ่งนี้อาจไม่ใช่เรื่องเล็กน้อย (และฉันไม่คุ้นเคยกับ Rx.NET มากพอที่จะรู้ว่าพวกเขาสามารถพิสูจน์ได้จากสเปคเพียงอย่างเดียว) แต่มันเป็นการเริ่มต้นที่ดี เพื่ออำนวยความสะดวกในส่วนที่เหลือของการสนทนานี้สมมติว่ากฎหมาย monad มีไว้ในกรณีนี้
ฟรี Monads
ไม่มีเอกพจน์ "ฟรี monad" แต่พระฟรีเป็นชั้นของพระที่สร้างขึ้นจาก functors นั่นคือเมื่อได้รับ functor F
เราสามารถรับ monad สำหรับF
(เช่น monad ฟรีของF
) โดยอัตโนมัติ
functors
เช่นเดียวกับ monads ฟังก์ชั่นสามารถกำหนดโดยสามรายการต่อไปนี้:
- ประเภทข้อมูลพารามิเตอร์กว่าตัวแปรชนิดเดียวที่ไม่ จำกัด
สองการดำเนินงาน:
pure
ห่อค่าที่บริสุทธิ์เข้าไปใน functor นี่คล้ายกับpure
สำหรับ monad ในความเป็นจริงสำหรับ functors ที่เป็น monads ทั้งสองควรเหมือนกัน
fmap
จับคู่ค่าในอินพุตกับค่าใหม่ในเอาต์พุตผ่านฟังก์ชันที่กำหนด มันคือลายเซ็น:
F<B> fmap(Func<A, B> f, F<A> fv)
เช่นเดียวกับ monads หน้าที่ต้องปฏิบัติตามกฎหมายของ functor
คล้ายกับ monads เราสามารถจำลอง functionors ผ่านทางอินเตอร์เฟสต่อไปนี้:
interface Functor<F> {
F<T> pure(T v);
F<B> fmap(Func<A, B> f, F<A> fv);
}
ตอนนี้เนื่องจาก monads เป็น sub-class ของ functors เราสามารถ refactor ได้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
และ Monads ฟรี
ตอนนี้ตั้งแต่เราได้กำหนดไว้สำหรับ monad IObservable
และตั้งแต่ monads เป็นชั้นย่อยของ functors มันตามที่เราจะต้องสามารถที่จะกำหนดเช่น functor 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);
}
}
ตอนนี้เราได้กำหนด functor ไว้IObservable
แล้วเราสามารถสร้าง monad ฟรีจาก functor นั้นได้ และนั่นคือวิธีการที่IObservable
เกี่ยวข้องกับ monads ฟรี - คือว่าเราสามารถสร้าง monad IObservable
ฟรีจาก
Cont
กับที่ฉันเห็น monad แนะนำว่าไม่สามารถแสดงออกผ่าน monad ได้ฟรีใคร ๆ ก็คงคิดว่า FRP นั้นเป็นได้ ที่สามารถเกือบทุกอย่างอื่น