ใน C # Monad คืออะไร


190

วันนี้มีการพูดคุยกันมากมายเกี่ยวกับพระ ฉันได้อ่านบทความ / บล็อกโพสต์ไม่กี่ แต่ฉันไม่สามารถไปไกลพอกับตัวอย่างของพวกเขาเข้าใจแนวคิดอย่างเต็มที่ เหตุผลก็คือ monads เป็นแนวคิดเกี่ยวกับภาษาที่ใช้งานได้และทำให้ตัวอย่างเป็นภาษาที่ฉันไม่ได้ทำงานด้วย (เนื่องจากฉันไม่ได้ใช้ภาษาเชิงหน้าที่ในเชิงลึก) ฉันไม่สามารถเข้าใจไวยากรณ์อย่างลึกซึ้งพอที่จะติดตามบทความอย่างเต็มที่ ... แต่ฉันสามารถบอกได้ว่ามีบางสิ่งที่คุ้มค่าที่จะเข้าใจ

อย่างไรก็ตามฉันรู้ C # ค่อนข้างดีรวมถึงการแสดงออกแลมบ์ดาและคุณสมบัติการทำงานอื่น ๆ ฉันรู้ว่า C # มีคุณลักษณะการทำงานบางส่วนเท่านั้นดังนั้นอาจไม่สามารถแสดง monads ใน C # ได้

อย่างไรก็ตามแน่นอนว่ามันเป็นไปได้ที่จะถ่ายทอดแนวคิดนี้? อย่างน้อยฉันก็หวังเช่นนั้น บางทีคุณสามารถนำเสนอตัวอย่าง C # เป็นรากฐานแล้วอธิบายสิ่งที่นักพัฒนา C # ต้องการให้เขาทำจากที่นั่น แต่ทำไม่ได้เพราะภาษาขาดคุณสมบัติการเขียนโปรแกรมที่ใช้งานได้ มันน่าอัศจรรย์เพราะมันสื่อความตั้งใจและประโยชน์ของพระสงฆ์ ดังนั้นนี่คือคำถามของฉัน: อะไรคือคำอธิบายที่ดีที่สุดที่คุณสามารถมอบให้กับนักพัฒนา C # 3

ขอบคุณ!

(แก้ไข: โดยวิธีการที่ฉันรู้ว่ามีอย่างน้อย 3 "อะไรคือ monad" คำถามอยู่แล้วดังนั้น แต่ฉันเผชิญปัญหาเดียวกันกับพวกเขา ... ดังนั้นคำถามนี้เป็นสิ่งที่จำเป็น imo เพราะ C # -developer โฟกัสขอบคุณ)


โปรดทราบว่าจริง ๆ แล้วมันคือนักพัฒนา C # 3.0 อย่าเข้าใจผิดกับ. NET 3.5 นอกจากนั้นคำถามที่ดี
Razzie

4
เป็นค่าที่ชี้ให้เห็นว่าการแสดงออกแบบสอบถาม LINQ เป็นตัวอย่างของพฤติกรรม monadic ใน C # 3 #
4322 Erik Forbes

1
ฉันยังคิดว่ามันเป็นคำถามที่ซ้ำกัน หนึ่งในคำตอบในstackoverflow.com/questions/2366/can-anyone-explain-monadsลิงก์ไปที่ channel9vip.orcsweb.com/shows/Going+Deep/ …ที่หนึ่งในความคิดเห็นมีตัวอย่าง C # ที่ดีมาก :)
jalf

4
ถึงกระนั้นก็เป็นเพียงลิงค์เดียวจากคำตอบเดียวกับหนึ่งในคำถาม SO ฉันเห็นคุณค่าของคำถามที่เน้นไปที่นักพัฒนา C # มันเป็นสิ่งที่ฉันจะถามโปรแกรมเมอร์ที่ใช้งานได้เคยทำ C # ถ้าฉันรู้ดังนั้นมันจึงสมเหตุสมผลที่จะถามใน SO แต่ฉันก็เคารพในความคิดเห็นของคุณเช่นกัน
Charlie ดอกไม้

1
ไม่ใช่คำตอบเดียวที่คุณต้องการใช่ไหม ;) จุดของฉันเป็นเพียงหนึ่งในคำถามอื่น ๆ (และตอนนี้คำถามนี้เช่นกันดังนั้น) มีคำตอบเฉพาะ C # - (ซึ่งดูเหมือนจะเขียนดีจริง ๆ จริง ๆ อาจเป็นคำอธิบายที่ดีที่สุดที่ฉันเคยเห็น)
jalf

คำตอบ:


147

สิ่งที่คุณทำในการเขียนโปรแกรมทั้งวันคือการรวมฟังก์ชั่นบางอย่างเข้าด้วยกันเพื่อสร้างฟังก์ชั่นที่ใหญ่กว่าจากพวกเขา โดยปกติแล้วคุณจะไม่เพียง แต่มีฟังก์ชั่นในกล่องเครื่องมือของคุณเท่านั้น แต่ยังรวมถึงสิ่งอื่น ๆ เช่นโอเปอเรเตอร์การกำหนดตัวแปรและอื่น ๆ แต่โดยทั่วไปโปรแกรมของคุณจะรวม "การคำนวณ" จำนวนมากเข้าด้วยกัน

Monad เป็นวิธีที่จะทำสิ่งนี้ "รวมการคำนวณ"

โดยปกติแล้ว "โอเปอเรเตอร์" ขั้นพื้นฐานที่สุดของคุณในการรวมสองการคำนวณเข้าด้วยกันคือ;:

a; b

เมื่อคุณพูดแบบนี้คุณหมายถึง "ก่อนอื่นให้ทำaแล้วb" ผลลัพธ์a; bคือการคำนวณที่สามารถรวมเข้ากับสิ่งอื่น ๆ ได้อีกครั้ง นี่เป็น monad ที่เรียบง่ายมันเป็นวิธีการคำนวณขนาดเล็กเพื่อคอมโบที่ใหญ่กว่า คำ;พูดที่ว่า "ทำสิ่งที่อยู่ทางซ้ายแล้วทำสิ่งที่ถูกต้อง"

อีกสิ่งหนึ่งที่สามารถมองเห็นเป็น monad .ในภาษาเชิงวัตถุเป็น บ่อยครั้งที่คุณพบสิ่งเช่นนี้:

a.b().c().d()

.โดยทั่วไปหมายถึง "การประเมินการคำนวณทางด้านซ้ายและจากนั้นเรียกวิธีการทางด้านขวาบนผลมาจากการที่ว่า" เป็นอีกวิธีในการรวมฟังก์ชั่น / การคำนวณเข้าด้วยกันซับซ้อนกว่า;เล็กน้อย และแนวคิดของการผูกมัดสิ่งต่าง ๆ เข้าด้วยกัน.เป็นแบบ monad เนื่องจากเป็นการรวมสองการคำนวณเข้าด้วยกันเป็นการคำนวณใหม่

Monad อื่นที่ค่อนข้างธรรมดาที่ไม่มีไวยากรณ์พิเศษคือรูปแบบนี้:

rv = socket.bind(address, port);
if (rv == -1)
  return -1;

rv = socket.connect(...);
if (rv == -1)
  return -1;

rv = socket.send(...);
if (rv == -1)
  return -1;

ค่าส่งคืน -1 หมายถึงความล้มเหลว แต่ไม่มีวิธีที่เป็นนามธรรมในการสรุปการตรวจสอบข้อผิดพลาดแม้ว่าคุณจะมีการเรียก API จำนวนมากที่คุณจำเป็นต้องรวมในรูปแบบนี้ นี่เป็นเพียง monad อื่นที่รวมการเรียกฟังก์ชันตามกฎ "ถ้าฟังก์ชันทางซ้ายส่งคืน -1 ให้ส่งคืน -1 ตัวเราเองมิฉะนั้นจะเรียกใช้ฟังก์ชันทางด้านขวา" หากเรามีโอเปอเรเตอร์>>=ที่ทำสิ่งนี้เราก็สามารถเขียนได้:

socket.bind(...) >>= socket.connect(...) >>= socket.send(...)

มันจะทำให้สิ่งต่าง ๆ สามารถอ่านได้มากขึ้นและช่วยในการสรุปวิธีพิเศษของเราในการรวมฟังก์ชั่นเพื่อให้เราไม่จำเป็นต้องทำซ้ำตัวเองซ้ำแล้วซ้ำอีก

และยังมีอีกหลายวิธีในการรวมฟังก์ชั่น / การคำนวณที่มีประโยชน์ในรูปแบบทั่วไปและสามารถสรุปใน monad ทำให้ผู้ใช้ของ monad สามารถเขียนรหัสที่กระชับและชัดเจนมากขึ้นตั้งแต่การเก็บหนังสือและการจัดการของ ฟังก์ชั่นที่ใช้จะทำใน monad

ตัวอย่างข้างต้น>>=สามารถขยายไปยัง "ทำการตรวจสอบข้อผิดพลาดแล้วโทรทางด้านขวาบนซ็อกเก็ตที่เราได้รับเป็นอินพุต" เพื่อที่เราจะได้ไม่ต้องระบุsocketจำนวนครั้งอย่างชัดเจน:

new socket() >>= bind(...) >>= connect(...) >>= send(...);

คำจำกัดความที่เป็นทางการนั้นซับซ้อนกว่านี้เล็กน้อยเนื่องจากคุณต้องกังวลเกี่ยวกับวิธีการรับผลลัพธ์ของฟังก์ชั่นหนึ่งเป็นอินพุตไปยังอีกฟังก์ชันหนึ่งหากฟังก์ชันนั้นต้องการอินพุตนั้นและเนื่องจากคุณต้องการให้แน่ใจว่าฟังก์ชันที่คุณรวมเข้าด้วยกัน วิธีที่คุณพยายามรวมมันไว้ใน monad ของคุณ แต่แนวคิดพื้นฐานก็คือให้คุณรวมวิธีการต่าง ๆ เข้าด้วยกันอย่างเป็นทางการ


28
คำตอบที่ดี! ฉันจะโยนใบเสนอราคาโดย Oliver Steele พยายามเชื่อมโยง Monads กับผู้ให้บริการมากเกินไปà la C ++ หรือ C #: Monads อนุญาตให้คุณโหลด ';' มากเกินไป ผู้ประกอบการ
Jörg W Mittag

6
@ JörgWMittagฉันอ่านคำพูดนั้นมาก่อน แต่มันฟังดูเหมือนเรื่องไร้สาระที่โหดร้ายมากเกินไป ตอนนี้ฉันเข้าใจพระและอ่านคำอธิบายของวิธีการ ';' คือหนึ่งฉันเข้าใจแล้ว แต่ฉันคิดว่ามันเป็นเหตุผลที่ไม่มีเหตุผลสำหรับนักพัฒนาที่จำเป็นที่สุด ';' ไม่ถูกมองว่าเป็นโอเปอเรเตอร์อีกต่อไปกว่า // เป็นมากที่สุด
จิมมี่ฮอฟฟา

2
คุณแน่ใจหรือไม่ว่าคุณรู้ว่า monad คืออะไร Monads ไม่ใช่ "ฟังก์ชัน" หรือการคำนวณมีกฎสำหรับ monads
หลุยส์

ใน;ตัวอย่างของคุณ: แมปวัตถุ / ชนิด;ข้อมูลใด (คิดว่าListแผนที่Tเป็นList<T>) ลักษณะของ;แผนที่ / ฟังก์ชันระหว่างวัตถุ / ชนิดข้อมูลอย่างไร อะไรคือสิ่งที่pure, join, bindสำหรับ;?
Micha Wiedenmann

44

เป็นเวลาหนึ่งปีแล้วที่ฉันโพสต์คำถามนี้ หลังจากโพสต์แล้วฉันก็ไปที่ Haskell สักสองสามเดือน ฉันสนุกกับมันอย่างมาก แต่ฉันก็เก็บมันไว้เหมือนที่ฉันพร้อมที่จะเจาะเข้าไปใน Monads ฉันกลับไปทำงานและมุ่งเน้นไปที่เทคโนโลยีที่โครงการของฉันต้องการ

และเมื่อคืนนี้ฉันกลับมาอ่านคำตอบเหล่านี้อีกครั้ง สิ่งสำคัญที่สุดคือผมอีกครั้งอ่านเฉพาะ C # ตัวอย่างในส่วนความเห็นข้อความของวิดีโอไบรอันเบคค์คนที่กล่าวถึงข้างต้น มันชัดเจนมากและให้แสงสว่างที่ฉันตัดสินใจโพสต์ไว้ที่นี่โดยตรง

เพราะความคิดเห็นนี้ไม่เพียง แต่ฉันรู้สึกเหมือนฉันเข้าใจว่าสิ่งที่ Monads เป็น ... ฉันรู้ฉันได้เขียนจริงบางสิ่งบางอย่างใน C # ที่มี Monads ... หรืออย่างน้อยก็ใกล้มากและมุ่งมั่นที่จะแก้ปัญหาเดียวกัน

ดังนั้นนี่คือความคิดเห็น - นี่คือทั้งหมดที่อ้างโดยตรงจากความคิดเห็นที่นี่โดยsylvan :

นี่มันเท่ห์ดี มันเป็นนามธรรมเล็กน้อย ฉันนึกภาพคนที่ไม่รู้ว่าพระสงฆ์สับสนอะไรอยู่แล้วเนื่องจากขาดตัวอย่างที่แท้จริง

ดังนั้นให้ฉันพยายามที่จะปฏิบัติตามและเพื่อให้ชัดเจนจริงๆฉันจะทำตัวอย่างใน C # ถึงแม้ว่ามันจะดูน่าเกลียด ฉันจะเพิ่ม Haskell ที่เทียบเท่ากันในตอนท้ายและแสดงให้คุณเห็นน้ำตาล Haskell syntactic ที่ยอดเยี่ยมซึ่งเป็นที่ที่ IMO พระเริ่มเริ่มมีประโยชน์จริงๆ

โอเคดังนั้นหนึ่งใน Monads ที่ง่ายที่สุดจึงถูกเรียกว่า "บางที monad" ใน Haskell ใน C # Nullable<T>ชนิดที่อาจจะเรียกว่า โดยพื้นฐานแล้วมันเป็นคลาสเล็ก ๆ ที่เพิ่งสรุปแนวคิดของค่าที่ใช้ได้และมีค่าหรือเป็น "โมฆะ" และไม่มีค่า

สิ่งที่มีประโยชน์ที่จะติดอยู่ภายใน monad สำหรับการรวมค่าประเภทนี้คือแนวคิดของความล้มเหลว นั่นคือเราต้องการให้สามารถดูค่า nullable หลาย ๆ ค่าและส่งคืนได้nullทันทีที่ค่าใดค่าหนึ่งเป็นโมฆะ สิ่งนี้อาจมีประโยชน์หากคุณค้นหาคีย์จำนวนมากในพจนานุกรมหรือบางสิ่งและท้ายที่สุดคุณต้องการประมวลผลผลลัพธ์ทั้งหมดและรวมเข้าด้วยกัน แต่ถ้าปุ่มใด ๆ ไม่อยู่ในพจนานุกรม คุณต้องการที่จะกลับมาnullสำหรับสิ่งทั้งหมด มันน่าเบื่อที่ต้องตรวจสอบการค้นหาแต่ละครั้งnullและส่งคืนด้วยตนเอง ดังนั้นเราจึงสามารถซ่อนการตรวจสอบนี้ภายในตัวดำเนินการเชื่อมโยง (ซึ่งเป็นประเภทของพระสงฆ์เราซ่อนการเก็บหนังสือไว้ในตัวดำเนินการผูกซึ่งทำให้รหัสง่ายขึ้น ใช้เนื่องจากเราสามารถลืมรายละเอียด)

นี่คือโปรแกรมที่กระตุ้นทุกสิ่ง (ฉันจะให้คำจำกัดความ Bindต่อมานี่เป็นเพียงการแสดงให้คุณเห็นว่าทำไมมันถึงดีมาก)

 class Program
    {
        static Nullable<int> f(){ return 4; }        
        static Nullable<int> g(){ return 7; }
        static Nullable<int> h(){ return 9; }


        static void Main(string[] args)
        {
            Nullable<int> z = 
                        f().Bind( fval => 
                            g().Bind( gval => 
                                h().Bind( hval =>
                                    new Nullable<int>( fval + gval + hval ))));

            Console.WriteLine(
                    "z = {0}", z.HasValue ? z.Value.ToString() : "null" );
            Console.WriteLine("Press any key to continue...");
            Console.ReadKey();
        }
    }

ตอนนี้ไม่สนใจสักครู่ว่ามีการสนับสนุนสำหรับการทำเช่นนี้Nullableใน C # (คุณสามารถเพิ่ม ints nullable ด้วยกันและคุณจะได้รับ null ถ้าทั้งสองเป็นโมฆะ) สมมติว่าไม่มีคุณสมบัติดังกล่าวและเป็นเพียงคลาสที่ผู้ใช้กำหนดเองโดยไม่มีเวทมนต์พิเศษ ประเด็นก็คือเราสามารถใช้Bindฟังก์ชั่นในการผูกตัวแปรกับเนื้อหาที่มีNullableค่าของเราแล้วแกล้งทำเป็นว่าไม่มีอะไรแปลก ๆ เกิดขึ้นและใช้พวกมันเหมือน int ปกติและเพิ่มพวกมันเข้าด้วยกัน เราห่อผลใน nullable ที่สิ้นสุดและ nullable ที่อาจจะเป็นโมฆะ (ถ้ามีของf, gหรือhผลตอบแทน null) หรือมันจะเป็นผลมาจากข้อสรุปf, gและhด้วยกัน. (นี่คล้ายกับวิธีที่เราสามารถผูกแถวในฐานข้อมูลกับตัวแปรใน LINQ และทำสิ่งต่าง ๆ กับมันปลอดภัยในความรู้ที่Bindผู้ประกอบการจะทำให้แน่ใจว่าตัวแปรจะผ่านค่าแถวที่ถูกต้องเท่านั้น)

คุณสามารถเล่นกับสิ่งนี้และเปลี่ยนแปลงใด ๆ ของf, gและhเพื่อคืนค่าว่างและคุณจะเห็นว่าสิ่งทั้งหมดจะคืนค่าว่าง

เห็นได้ชัดว่าผู้ประกอบการเชื่อมต้องทำการตรวจสอบนี้กับเราและประกันการคืนค่าว่างถ้าพบค่า Null และส่งผ่านค่าภายในNullableโครงสร้างลงในแลมบ์ดา

นี่คือBindผู้ประกอบการ:

public static Nullable<B> Bind<A,B>( this Nullable<A> a, Func<A,Nullable<B>> f ) 
    where B : struct 
    where A : struct
{
    return a.HasValue ? f(a.Value) : null;
}

ประเภทที่นี่เหมือนกับในวิดีโอ มันใช้เวลาM a ( Nullable<A>ในไวยากรณ์ C # สำหรับกรณีนี้) และฟังก์ชั่นจากaถึง M b( Func<A, Nullable<B>>ในไวยากรณ์ C #) และมันส่งกลับM b ( Nullable<B>)

รหัสจะตรวจสอบว่าค่า nullable นั้นมีค่าหรือไม่และถ้าแยกออกมาและส่งไปยังฟังก์ชันนั้นมิฉะนั้นจะส่งคืนค่า null ซึ่งหมายความว่าBindผู้ประกอบการจะจัดการกับตรรกะการตรวจสอบโมฆะทั้งหมดสำหรับเรา ถ้าหากว่าค่าที่เราเรียก Bindใช้นั้นไม่ใช่ค่า Null ค่านั้นจะถูก "ส่งไปตาม" ไปยังฟังก์ชั่นแลมบ์ดาเราจะประกันตัวก่อนเวลาและการแสดงออกทั้งหมดจะเป็นโมฆะ นี้จะช่วยให้โค้ดที่เราเขียนโดยใช้ monad ที่จะเป็นอิสระโดยสิ้นเชิงของพฤติกรรม null การตรวจสอบนี้เราเพียงแค่ใช้Bindและได้รับตัวแปรที่ถูกผูกไว้กับค่าภายในค่าเอก ( fval, gvalและhvalในรหัสตัวอย่าง) และเราสามารถใช้พวกเขาปลอดภัย ในความรู้ที่Bindจะตรวจสอบพวกเขาเป็นโมฆะก่อนที่จะผ่านพวกเขาไป

มีตัวอย่างอื่น ๆ ของสิ่งที่คุณสามารถทำได้กับ Monad ตัวอย่างเช่นคุณสามารถทำให้Bindโอเปอเรเตอร์ดูแลอินพุตสตรีมของตัวละครและใช้มันเพื่อเขียนตัวแยกวิเคราะห์ parser แต่ละ Combinator parser แล้วได้อย่างสมบูรณ์ลบเลือนไปสิ่งที่ต้องการกลับมาติดตามความล้มเหลว parser ฯลฯ และเพียงแค่รวม parsers ขนาดเล็กด้วยกันราวกับว่าสิ่งที่จะไม่ผิดไป, ตู้เซฟในความรู้ว่าการดำเนินงานที่ฉลาดของBindทุกประเภทออกทั้งหมดตรรกะที่อยู่เบื้องหลัง บิตยาก หลังจากนั้นอาจมีบางคนเพิ่มการบันทึกลงใน Monad แต่รหัสที่ใช้ monad จะไม่เปลี่ยนแปลงเนื่องจากเวทมนตร์ทั้งหมดเกิดขึ้นในคำจำกัดความของBindผู้ปฏิบัติงานส่วนที่เหลือของรหัสไม่เปลี่ยนแปลง

ในที่สุดนี่คือการใช้รหัสเดียวกันใน Haskell ( -- เริ่มบรรทัดความคิดเห็น)

-- Here's the data type, it's either nothing, or "Just" a value
-- this is in the standard library
data Maybe a = Nothing | Just a

-- The bind operator for Nothing
Nothing >>= f = Nothing
-- The bind operator for Just x
Just x >>= f = f x

-- the "unit", called "return"
return = Just

-- The sample code using the lambda syntax
-- that Brian showed
z = f >>= ( \fval ->
     g >>= ( \gval ->  
     h >>= ( \hval -> return (fval+gval+hval ) ) ) )

-- The following is exactly the same as the three lines above
z2 = do 
   fval <- f
   gval <- g
   hval <- h
   return (fval+gval+hval)

อย่างที่คุณเห็นdoสัญกรณ์ที่ดีในตอนท้ายทำให้มันดูเหมือนรหัสบังคับตรง และนี่คือการออกแบบ Monads สามารถใช้ห่อหุ้มสิ่งที่มีประโยชน์ทั้งหมดในการเขียนโปรแกรมที่จำเป็น (สถานะที่ไม่แน่นอน, IO ฯลฯ ) และใช้โดยใช้ไวยากรณ์ที่คล้ายกับคำสั่งที่ดี แต่อยู่หลังม่านมันเป็นเพียง monads และการใช้งานที่ชาญฉลาดของผู้ประกอบการผูกมัด! สิ่งดีๆที่คุณสามารถใช้ monads ของคุณเองโดยการดำเนินการและ>>= returnและถ้าคุณทำเช่นนั้นพระเหล่านั้นก็จะสามารถใช้doสัญกรณ์ซึ่งหมายความว่าคุณสามารถเขียนภาษาเล็ก ๆ ของคุณโดยเพียงแค่กำหนดสองฟังก์ชั่น!


3
โดยส่วนตัวฉันชอบรุ่นของ F # ของ monad แต่ในทั้งสองกรณีมันยอดเยี่ยม
ChaosPandion

3
ขอบคุณที่กลับมาที่นี่และอัปเดตโพสต์ของคุณ มันคือการติดตามสิ่งเหล่านี้ซึ่งช่วยโปรแกรมเมอร์ที่มองเข้าไปในพื้นที่ที่เฉพาะเจาะจงเข้าใจจริง ๆ ว่าโปรแกรมเมอร์เพื่อนในท้ายที่สุดคิดว่าพื้นที่นั้นอย่างไรแทนที่จะมี "ฉันจะทำอย่างไร x ในเทคโนโลยี y" เพื่อออกไป คุณ da man!
kappasims

ฉันได้ใช้เส้นทางเดียวกับที่คุณได้มาและมาถึงสถานที่เดียวกันกับการทำความเข้าใจกับพระที่กล่าวว่านี่เป็นคำอธิบายที่ดีที่สุดเพียงคำเดียวเกี่ยวกับพฤติกรรมการผูกมัดของ monad ที่ฉันเคยเห็นสำหรับนักพัฒนาที่จำเป็น แม้ว่าฉันคิดว่าคุณไม่ได้สัมผัสทุกสิ่งทุกอย่างเกี่ยวกับ monads ซึ่งอธิบายเพิ่มเติมเล็กน้อยโดย sth
จิมมี่ฮอฟฟา

@Jimmy Hoffa - ไม่ต้องสงสัยเลยว่าคุณพูดถูก ผมคิดว่าจริงๆเข้าใจพวกเขาลึกวิธีที่ดีที่สุดคือการเริ่มต้นการใช้พวกเขาเป็นจำนวนมากและได้รับประสบการณ์ ฉันยังไม่มีโอกาสนั้น แต่หวังว่าจะได้ในไม่ช้า
ชาร์ลีดอกไม้

ดูเหมือนว่า monad จะเป็นเพียงนามธรรมในระดับที่สูงขึ้นในแง่ของการเขียนโปรแกรมหรือเป็นเพียงนิยามฟังก์ชันที่ต่อเนื่องและไม่แตกต่างกันในวิชาคณิตศาสตร์ ไม่ว่าจะด้วยวิธีใดก็ตามพวกเขาไม่ใช่แนวคิดใหม่โดยเฉพาะในวิชาคณิตศาสตร์
เหลียง

11

Monad คือการประมวลผลรอตัดบัญชีเป็นหลัก หากคุณกำลังพยายามเขียนโค้ดที่มีผลข้างเคียง (เช่น I / O) ในภาษาที่ไม่อนุญาตให้ใช้และอนุญาตให้ใช้การคำนวณที่บริสุทธิ์เพียงอย่างเดียวหนึ่งดอดจ์ก็จะพูดว่า "โอเคฉันรู้ว่าคุณจะไม่เกิดผลข้างเคียง สำหรับฉัน แต่คุณสามารถโปรดคำนวณว่าจะเกิดอะไรขึ้นถ้าคุณทำ? "

มันเป็นการโกง

ตอนนี้คำอธิบายนั้นจะช่วยให้คุณเข้าใจเจตนาของภาพพระใหญ่ แต่มารนั้นอยู่ในรายละเอียด วิธีการว่าทำคุณคำนวณผลกระทบหรือไม่ บางครั้งมันก็ไม่สวย

วิธีที่ดีที่สุดในการให้ภาพรวมของวิธีการที่คนบางคนคุ้นเคยกับการเขียนโปรแกรมที่จำเป็นคือการบอกว่ามันทำให้คุณอยู่ใน DSL ซึ่งการดำเนินการที่ดูเหมือน syntactically เหมือนสิ่งที่คุณคุ้นเคยกับการใช้ monad แทนการสร้างฟังก์ชั่น สิ่งที่คุณต้องการถ้าคุณสามารถทำได้ (เช่น) เขียนลงในไฟล์เอาต์พุต เกือบ (แต่ไม่ใช่จริงๆ) ราวกับว่าคุณกำลังสร้างรหัสในสตริงเพื่อเป็น eval'd ในภายหลัง


1
เหมือนในหนังสือ I Robot หรือไม่? ที่นักวิทยาศาสตร์ถามคอมพิวเตอร์เพื่อคำนวณการเดินทางในอวกาศและขอให้พวกเขาข้ามกฎบางอย่าง? :) :) :) :)
OscarRyz

3
Hmm, A Monad สามารถใช้สำหรับการประมวลผลที่เลื่อนออกไปและห่อหุ้มฟังก์ชั่นเอฟเฟกต์ข้างเคียงซึ่งเป็นครั้งแรกที่ใช้จริงใน Haskell แต่จริงๆแล้วมันเป็นรูปแบบทั่วไปที่กว้างกว่า การใช้งานทั่วไปอื่น ๆ รวมถึงการจัดการข้อผิดพลาดและการจัดการสถานะ น้ำตาล syntactic (ทำใน Haskell, การคำนวณการแสดงออกใน F #, ไวยากรณ์ Linq ใน C #) เป็นเพียงที่และพื้นฐานให้ Monads เช่นนี้
Mike Hadlow

@MikeHadlow: อินสแตนซ์ monad สำหรับการจัดการข้อผิดพลาด ( MaybeและEither e) และการจัดการสถานะ ( State s, ST s) ทำให้ฉันเป็นกรณีพิเศษของ "โปรดคำนวณสิ่งที่จะเกิดขึ้นหากคุณทำ [ผลข้างเคียงสำหรับฉัน]" อีกตัวอย่างหนึ่งก็คือ nondeterminism ( [])
pyon

นี้อยู่ตรงขวา; ด้วยการเพิ่มเติมหนึ่ง (ดีสอง) ว่าเป็นE DSL, เช่นDSL ที่ฝังตัว , เพราะค่า "monadic" แต่ละค่าเป็นค่าที่ถูกต้องของภาษา "บริสุทธิ์" ของคุณเอง, ยืนเพื่อการคำนวณที่ไม่บริสุทธิ์ " นอกจากเอก "ผูก" สร้างที่มีอยู่ในภาษาบริสุทธิ์ของคุณซึ่งช่วยให้คุณห่วงโซ่บริสุทธิ์ก่อสร้างของค่าดังกล่าวที่แต่ละคนจะถูกเรียกด้วยผลจากการคำนวณก่อนหน้านี้ระบุเมื่อคำนวณรวมทั้งมีการ "ทำงาน" ซึ่งหมายความว่าเรามีความสามารถในการแยกสาขากับผลลัพธ์ในอนาคต (หรือในกรณีใด ๆ ของไทม์ไลน์ "Run" แยกต่างหาก)
Will Ness

แต่สำหรับโปรแกรมเมอร์มันหมายความว่าเราสามารถตั้งโปรแกรมใน EDSL ในขณะที่ผสมกับการคำนวณบริสุทธิ์ของภาษาบริสุทธิ์ของเรา แซนวิชหลายชั้นเป็นแซนวิชหลายชั้น มันเป็นเรื่องที่ง่าย
Will Ness

4

ฉันแน่ใจว่าผู้ใช้รายอื่นจะโพสต์ในเชิงลึก แต่ฉันพบว่าวิดีโอนี้มีประโยชน์ในระดับหนึ่ง แต่ฉันจะบอกว่าฉันยังไม่ถึงจุดที่มีความคล่องแคล่วกับแนวคิดที่ฉันสามารถ (หรือควร) เริ่มแก้ไข ปัญหาอย่างสังหรณ์ใจกับ Monads


1
สิ่งที่ฉันพบว่ามีประโยชน์มากกว่าคือความคิดเห็นที่มีตัวอย่าง C # ด้านล่างวิดีโอ
jalf

ฉันไม่รู้เรื่องเกี่ยวกับสิ่งที่เป็นประโยชน์มากขึ้นแต่มันก็นำความคิดมาใช้ในทางปฏิบัติ
TheMissingLINQ

0

คุณสามารถคิด monad เป็นC #interfaceที่เรียนต้องใช้ นี่คือคำตอบอย่างจริงจังที่ไม่สนใจหมวดหมู่ทฤษฎีทางคณิตศาสตร์ทั้งหมดที่อยู่เบื้องหลังสาเหตุที่คุณต้องการเลือกให้มีการประกาศเหล่านี้ในส่วนต่อประสานของคุณและไม่สนใจเหตุผลทั้งหมดที่คุณต้องการมีพระในภาษาที่พยายามหลีกเลี่ยงผลข้างเคียง แต่ฉันพบว่าเป็นการเริ่มต้นที่ดีในฐานะคนที่เข้าใจอินเตอร์เฟส (C #)


คุณสามารถทำอย่างละเอียด? อินเทอร์เฟซที่เกี่ยวข้องกับ Monads คืออะไร
Joel Coehoorn

2
ฉันคิดว่าการโพสต์บล็อกนั้นมีหลายย่อหน้าที่เกี่ยวข้องกับคำถามนั้น
hao

0

ดูคำตอบของฉันที่ "Monad คืออะไร"

มันเริ่มต้นด้วยตัวอย่างที่สร้างแรงบันดาลใจทำงานผ่านตัวอย่างมาตัวอย่างของ monad และกำหนด "monad" อย่างเป็นทางการ

มันจะไม่มีความรู้เกี่ยวกับการเขียนโปรแกรมฟังก์ชั่นและจะใช้ pseudocode กับfunction(argument) := expressionไวยากรณ์ที่มีการแสดงออกที่เป็นไปได้ง่ายที่สุด

โปรแกรม C # นี้เป็นการใช้งาน pseudocode monad (สำหรับการอ้างอิง: Mเป็นตัวสร้างประเภทfeedคือการดำเนินการ "ผูก" และwrapเป็นการดำเนินการ "ส่งคืน")

using System.IO;
using System;

class Program
{
    public class M<A>
    {
        public A val;
        public string messages;
    }

    public static M<B> feed<A, B>(Func<A, M<B>> f, M<A> x)
    {
        M<B> m = f(x.val);
        m.messages = x.messages + m.messages;
        return m;
    }

    public static M<A> wrap<A>(A x)
    {
        M<A> m = new M<A>();
        m.val = x;
        m.messages = "";
        return m;
    }

    public class T {};
    public class U {};
    public class V {};

    public static M<U> g(V x)
    {
        M<U> m = new M<U>();
        m.messages = "called g.\n";
        return m;
    }

    public static M<T> f(U x)
    {
        M<T> m = new M<T>();
        m.messages = "called f.\n";
        return m;
    }

    static void Main()
    {
        V x = new V();
        M<T> m = feed<U, T>(f, feed(g, wrap<V>(x)));
        Console.Write(m.messages);
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.