ใครบอกว่าต่อไปนี้ก่อน?
Monad เป็นเพียง monoid ในประเภท endofunctors ปัญหาคืออะไร
และในบันทึกย่อที่สำคัญน้อยกว่านี่คือความจริงและถ้าเป็นเช่นนั้นคุณสามารถให้คำอธิบายได้ (หวังว่าจะมีคนที่ไม่เข้าใจประสบการณ์ของ Haskell มาก)
ใครบอกว่าต่อไปนี้ก่อน?
Monad เป็นเพียง monoid ในประเภท endofunctors ปัญหาคืออะไร
และในบันทึกย่อที่สำคัญน้อยกว่านี่คือความจริงและถ้าเป็นเช่นนั้นคุณสามารถให้คำอธิบายได้ (หวังว่าจะมีคนที่ไม่เข้าใจประสบการณ์ของ Haskell มาก)
คำตอบ:
ประโยคเฉพาะนั้นคือโดย James Iry จากบทสรุปความบันเทิงที่ไม่สมบูรณ์และไม่ถูกต้องส่วนใหญ่ของประวัติศาสตร์การเขียนโปรแกรมภาษาซึ่งเขาได้กล่าวอ้างถึง Philip Wadler
ข้อความต้นฉบับมาจาก Saunders Mac Lane ในหมวดหมู่สำหรับนักคณิตศาสตร์ทำงานซึ่งเป็นหนึ่งในตำราพื้นฐานของหมวดหมู่ทฤษฎี ที่นี่มีอยู่ในบริบทซึ่งอาจเป็นสถานที่ที่ดีที่สุดในการเรียนรู้สิ่งที่มันหมายถึง
แต่ฉันจะแทง ประโยคเดิมคือ:
ทั้งหมดบอกว่า monad ใน X เป็นเพียง monoid ในหมวดหมู่ของ endofunctors ของ X ด้วยผลิตภัณฑ์×แทนที่ด้วยองค์ประกอบของ endofunctors และหน่วยที่กำหนดโดย endofunctor ตัวตน
Xนี่คือหมวดหมู่ Endofunctors มี functors จากหมวดหมู่เพื่อตัวเอง (ซึ่งมักจะทุก Functor s เท่าที่โปรแกรมเมอร์ทำงานมีความกังวลเนื่องจากพวกเขากำลังส่วนใหญ่ที่เกี่ยวข้องกับการเพียงหนึ่งหมวดหมู่; หมวดหมู่ของประเภท - แต่ฉันเชือนแช) แต่คุณสามารถจินตนาการหมวดหมู่อื่นซึ่งเป็นหมวดหมู่ของ "endofunctors on X " นี่คือหมวดหมู่ที่วัตถุคือ endofunctors และ morphisms เป็นการเปลี่ยนแปลงตามธรรมชาติ
และในบรรดา endofunctors บางคนอาจเป็นพระ อันไหนเป็นพระ อย่างแน่นอนคนที่มีmonoidalในความหมายเฉพาะ แทนที่จะสะกดการแมปที่ถูกต้องจาก monads ไปยัง monoids (เนื่องจาก Mac Lane ทำได้ดีกว่าที่ฉันคาดหวังมาก) ฉันจะใส่คำจำกัดความตามลำดับและให้คุณเปรียบเทียบ:
* -> *มีFunctorอินสแตนซ์)joinใน Haskell)returnใน Haskell)กับบิตของ squinting คุณอาจจะสามารถที่จะเห็นว่าทั้งสองของคำนิยามเหล่านี้เป็นกรณีเดียวกันแนวคิดนามธรรม
Sเป็นประเภทสิ่งที่คุณทำได้เมื่อเขียนฟังก์ชั่นf :: () -> Sก็คือเลือกประเภทของคำเฉพาะS("องค์ประกอบ" ของมันถ้าคุณต้องการ) และกลับมา มัน ... คุณไม่ได้รับข้อมูลจริงเกี่ยวกับการโต้แย้งดังนั้นจึงไม่มีวิธีที่จะเปลี่ยนแปลงพฤติกรรมของฟังก์ชัน ดังนั้นfจะต้องมีฟังก์ชั่นคงที่ซึ่งเพียงแค่คืนสิ่งเดิมทุกครั้ง ()("หน่วย") เป็นวัตถุเทอร์มินัลของหมวดหมู่Haskและมันไม่ใช่เรื่องบังเอิญว่ามีค่า 1 (ไม่แตกต่างกัน) ที่อาศัยอยู่
โดยสังหรณ์ใจฉันคิดว่าสิ่งที่คำศัพท์ทางคณิตศาสตร์แฟนซีพูดคือ:
หนังสือคือชุดของวัตถุและวิธีการรวมพวกเขา monoids ที่รู้จักกันดีคือ:
มีตัวอย่างที่ซับซ้อนกว่านี้ด้วย
นอกจากนี้monoid ทุกตัวจะมีตัวตนซึ่งเป็นองค์ประกอบ "no-op" ที่ไม่มีผลเมื่อคุณรวมเข้ากับสิ่งอื่น:
ในที่สุด monoid ต้องเชื่อมโยงกัน (คุณสามารถลดชุดค่าผสมที่มีความยาวได้ตามที่คุณต้องการตราบใดที่คุณไม่เปลี่ยนลำดับจากซ้ายไปขวาของวัตถุ) การเพิ่มคือตกลง ((5 + 3) +1 == 5+ (3+ 1)) แต่การลบไม่ใช่ ((5-3) -1! = 5- (3-1))
ทีนี้ลองพิจารณาชุดพิเศษชนิดและวิธีพิเศษในการรวมวัตถุ
สมมติว่าชุดของคุณมีวัตถุชนิดพิเศษ: ฟังก์ชั่น และฟังก์ชั่นเหล่านี้มีลายเซ็นที่น่าสนใจ: พวกมันไม่ได้นำตัวเลขไปเป็นตัวเลข แต่ละฟังก์ชั่นจะใช้ตัวเลขเป็นรายการตัวเลขในกระบวนการสองขั้นตอนแทน
ตัวอย่าง:
นอกจากนี้วิธีการรวมฟังก์ชั่นของเราเป็นพิเศษ วิธีง่ายๆที่จะรวมฟังก์ชั่นเป็นองค์ประกอบ : ลองตัวอย่างข้างต้นของเราและเขียนแต่ละฟังก์ชั่นด้วยตัวเอง:
ประเด็นสำคัญคือคุณสามารถรวมจำนวนเต็มสองจำนวนเพื่อให้ได้จำนวนเต็ม แต่คุณไม่สามารถเขียนสองฟังก์ชันและรับฟังก์ชั่นประเภทเดียวกันได้เสมอ (ฟังก์ชั่นที่มีประเภท-> a จะเขียน แต่a-> [a]จะไม่ได้)
ดังนั้นขอนิยามวิธีที่แตกต่างของการรวมฟังก์ชั่น เมื่อเรารวมสองฟังก์ชั่นเหล่านี้เราไม่ต้องการที่จะ "ตัดสองครั้ง" ผลลัพธ์
นี่คือสิ่งที่เราทำ เมื่อเราต้องการรวมสองฟังก์ชั่น F และ G เราจะทำตามกระบวนการนี้ (เรียกว่าการผูก ):
กลับไปที่ตัวอย่างของเรามารวมฟังก์ชั่น (ผูก) เข้ากับตัวเองโดยใช้วิธีใหม่ของฟังก์ชั่น "การผูก":
วิธีการรวมฟังก์ชั่นที่ซับซ้อนมากขึ้นนี้คือการเชื่อมโยง (ต่อจากการรวมองค์ประกอบของฟังก์ชั่นเมื่อคุณไม่ได้ทำสิ่งห่อหุ้มแฟนซี)
ผูกมันทั้งหมดเข้าด้วยกัน
มีหลายวิธีในการ "ห่อ" ผลลัพธ์ คุณสามารถสร้างรายการหรือตั้งค่าหรือทิ้งทั้งหมดยกเว้นผลลัพธ์แรกในขณะที่สังเกตว่าไม่มีผลลัพธ์ให้แนบ sidecar of state พิมพ์ข้อความบันทึก ฯลฯ
ฉันเล่นหลวมเล็กน้อยกับคำจำกัดความโดยหวังว่าจะได้ความคิดที่สำคัญข้ามไปได้โดยสัญชาตญาณ
ฉันได้ง่ายสิ่งเล็กน้อยโดยยืนยันว่า monad ของเราดำเนินการในการทำงานประเภท-> [เป็น] ในความเป็นจริง monads ทำงานในฟังก์ชั่นของประเภท-> mbแต่การวางนัยทั่วไปเป็นรายละเอียดทางเทคนิคที่ไม่ใช่ความเข้าใจหลัก
a -> [b]และc -> [d](คุณสามารถทำเช่นนี้หากb= c) นี้ไม่ได้ค่อนข้างอธิบายหนังสือ อันที่จริงแล้วมันคือการทำงานแบบแบนที่คุณอธิบายไว้แทนที่จะเป็นองค์ประกอบของฟังก์ชั่นซึ่งเป็น "ตัวดำเนินการโมโน"
a -> [a]นี้จะเป็น monoid (เพราะคุณจะลดหมวดหมู่ Kleisli เป็นวัตถุเดียวและหมวดหมู่ของวัตถุเดียวเท่านั้น เป็นคำจำกัดความที่ monoid!) แต่มันจะไม่จับภาพทั่วไปของ monad
อย่างแรกคือส่วนขยายและไลบรารีที่เราจะใช้:
{-# LANGUAGE RankNTypes, TypeOperators #-}
import Control.Monad (join)
ของเหล่านี้RankNTypesเป็นสิ่งเดียวที่จำเป็นอย่างยิ่งต่อไปนี้ ฉันเคยเขียนคำอธิบายRankNTypesว่าบางคนดูเหมือนจะมีประโยชน์ดังนั้นฉันจะพูดถึงสิ่งนั้น
การอ้างอิงคำตอบที่ยอดเยี่ยมของ Tom Crockettเรามี:
Monad คือ ...
- endofunctor, T: X -> X
- การเปลี่ยนแปลงตามธรรมชาติ, μ: T × T -> Tโดยที่×หมายถึงองค์ประกอบของ functor
- การเปลี่ยนแปลงตามธรรมชาติη: I -> Tโดยที่ฉันเป็นตัวตนของ endofunctor บนX
... เป็นไปตามกฎหมายเหล่านี้:
- μ (μ (T × T) × T)) = μ (T ×μ (T × T))
- μ (η (T)) = T = μ (T (η))
เราจะแปลสิ่งนี้เป็นรหัส Haskell ได้อย่างไร เรามาเริ่มกันด้วยแนวคิดของการเปลี่ยนแปลงตามธรรมชาติ :
-- | A natural transformations between two 'Functor' instances. Law:
--
-- > fmap f . eta g == eta g . fmap f
--
-- Neat fact: the type system actually guarantees this law.
--
newtype f :-> g =
Natural { eta :: forall x. f x -> g x }
ชนิดของรูปแบบf :-> gคล้ายคลึงกับประเภทฟังก์ชั่น แต่แทนที่จะคิดว่ามันเป็นฟังก์ชั่นระหว่างสองประเภท (ประเภท*) คิดว่ามันเป็นซึ่มส์ระหว่างสองfunctors (แต่ละชนิด* -> *) ตัวอย่าง:
listToMaybe :: [] :-> Maybe
listToMaybe = Natural go
where go [] = Nothing
go (x:_) = Just x
maybeToList :: Maybe :-> []
maybeToList = Natural go
where go Nothing = []
go (Just x) = [x]
reverse' :: [] :-> []
reverse' = Natural reverse
โดยทั่วไปใน Haskell การแปลงโดยธรรมชาติคือฟังก์ชั่นจากบางประเภทf xเป็นอีกประเภทหนึ่งg xซึ่งxตัวแปรประเภทคือ "ไม่สามารถเข้าถึงได้" ไปยังผู้โทร ดังนั้นสำหรับตัวอย่างเช่นsort :: Ord a => [a] -> [a]ไม่สามารถทำในการเปลี่ยนแปลงทางธรรมชาติเพราะมันเป็น "จู้จี้จุกจิก" aเกี่ยวกับประเภทที่เราอาจจะยกตัวอย่างสำหรับ วิธีหนึ่งที่ใช้งานง่ายที่ฉันมักจะใช้ในการคิดสิ่งนี้คือ:
ทีนี้ถ้าอย่างนั้นเรามาจัดการกับส่วนคำจำกัดความกันเถอะ
ประโยคแรกคือ "endofunctor, T: X -> X. " Functorใน Haskell ทุกคนเป็น endofunctor ในสิ่งที่ผู้คนเรียกว่า "หมวด Hask" ซึ่งวัตถุประเภท Haskell (ชนิด*) และมี morphisms เป็นฟังก์ชัน Haskell ฟังดูเหมือนประโยคที่ซับซ้อน แต่จริงๆแล้วมันเป็นเรื่องเล็กน้อย ทั้งหมดหมายความว่าเป็นที่Functor f :: * -> *ให้คุณสร้างประเภทf a :: *สำหรับใด ๆa :: *และฟังก์ชั่นfmap f :: f a -> f bออกจากใด ๆf :: a -> bและสิ่งเหล่านี้เป็นไปตามกฎหมาย functor
ประโยคที่สอง: Identityfunctor ใน Haskell (ซึ่งมาพร้อมกับแพลตฟอร์มดังนั้นคุณสามารถนำเข้าได้) ถูกกำหนดด้วยวิธีนี้:
newtype Identity a = Identity { runIdentity :: a }
instance Functor Identity where
fmap f (Identity a) = Identity (f a)
ดังนั้นการเปลี่ยนแปลงตามธรรมชาติη: I -> Tจากคำนิยามของ Tom Crockett สามารถเขียนได้ด้วยวิธีนี้Monadเช่นt:
return' :: Monad t => Identity :-> t
return' = Natural (return . runIdentity)
ประโยคที่สาม: องค์ประกอบของสองฟังก์ชั่นใน Haskell สามารถกำหนดได้ด้วยวิธีนี้ (ซึ่งมาพร้อมกับแพลตฟอร์ม):
newtype Compose f g a = Compose { getCompose :: f (g a) }
-- | The composition of two 'Functor's is also a 'Functor'.
instance (Functor f, Functor g) => Functor (Compose f g) where
fmap f (Compose fga) = Compose (fmap (fmap f) fga)
ดังนั้นการแปลงตามธรรมชาติμ: T × T -> Tจากนิยามของ Tom Crockett สามารถเขียนได้ดังนี้:
join' :: Monad t => Compose t t :-> t
join' = Natural (join . getCompose)
คำแถลงว่านี่เป็น monoid ในหมวดหมู่ของ endofunctors นั้นหมายความว่าCompose(นำไปใช้เพียงบางส่วนกับพารามิเตอร์สองตัวแรก) นั้นคือการเชื่อมโยงและนั่นIdentityคือองค์ประกอบตัวตน คือว่ามอร์ฟอสมีมอร์ฟิซึ่มดังต่อไปนี้:
Compose f (Compose g h) ~= Compose (Compose f g) hCompose f Identity ~= fCompose Identity g ~= gสิ่งเหล่านี้ง่ายต่อการพิสูจน์เพราะComposeและIdentityทั้งคู่ถูกกำหนดเป็นnewtypeและรายงาน Haskell กำหนดความหมายของnewtypeการเป็น isomorphism ระหว่างประเภทที่ถูกกำหนดและประเภทของการโต้แย้งไปยังตัวnewtypeสร้างข้อมูลของ ตัวอย่างเช่นลองพิสูจน์Compose f Identity ~= f:
Compose f Identity a
~= f (Identity a) -- newtype Compose f g a = Compose (f (g a))
~= f a -- newtype Identity a = Identity a
Q.E.D.
Naturalใหม่ฉันไม่สามารถเข้าใจได้ว่า(Functor f, Functor g)ข้อ จำกัด กำลังทำอะไร คุณอธิบายได้ไหม
Functorข้อ จำกัดเหล่านั้นออกไปเพราะไม่จำเป็น หากคุณไม่เห็นด้วยก็สามารถเพิ่มกลับได้
joinมีการกำหนดไว้ และนั่นjoinคือมอร์ฟิซึ่มประมาณการ แต่ฉันไม่แน่ใจ.
หมายเหตุ:ไม่นี่ไม่เป็นความจริง เมื่อถึงจุดหนึ่งก็มีความคิดเห็นเกี่ยวกับคำตอบนี้จากแดน Piponi ตัวเองบอกว่าสาเหตุและผลที่นี่ตรงข้ามแน่นอนว่าเขาเขียนบทความของเขาในการตอบสนอง quip ของ James Iry แต่ดูเหมือนว่ามันจะถูกลบออกบางทีอาจจะเป็นความคิดที่เป็นระเบียบ
ด้านล่างคือคำตอบเดิมของฉัน
มันค่อนข้างเป็นไปได้ที่ Iry ได้อ่านจาก Monoids ถึง Monadsซึ่งเป็นตำแหน่งที่ Dan Piponi (sigfpe) สร้าง monads จาก monoids ใน Haskell ด้วยการอภิปรายอย่างมากเกี่ยวกับทฤษฎีหมวดหมู่และกล่าวถึง "หมวดหมู่ของ endofunctors on Hask " ไม่ว่าในกรณีใดก็ตามใครก็ตามที่สงสัยว่าการที่ monad เป็น monoid ในประเภทของ endofunctors อาจได้ประโยชน์จากการอ่านที่มานี้
:-)หรือเป็นเราด้วยความรักหมายถึงพวกเขาในเว็บไซต์นี้เป็นผู้ดูแล
ผมมาโพสต์นี้โดยวิธีการที่ดีกว่าการทำความเข้าใจการอนุมานของคำพูดที่น่าอับอายจากเครื่อง Mac เลนของทฤษฎีหมวดหมู่สำหรับนักคณิตศาสตร์ทำงาน
ในการอธิบายสิ่งที่เป็นสิ่งที่มักจะมีประโยชน์เท่าเทียมกันเพื่ออธิบายสิ่งที่ไม่
ข้อเท็จจริงที่ว่า Mac Lane ใช้คำอธิบายเพื่ออธิบาย Monad หนึ่งอาจบ่งบอกว่ามันอธิบายบางสิ่งบางอย่างที่ไม่ซ้ำกับ monads อดทนกับฉัน เพื่อพัฒนาความเข้าใจที่กว้างขึ้นเกี่ยวกับคำแถลงนี้ผมเชื่อว่ามันต้องชัดเจนว่าเขาไม่ได้อธิบายสิ่งที่เป็นเอกลักษณ์ของพระสงฆ์ ข้อความนี้อธิบายถึงการใช้งานและลูกศรอย่างเท่าเทียมกัน ด้วยเหตุผลเดียวกันเราสามารถมี monoids สองตัวบน Int (Sum และ Product) เราสามารถมี monoids หลายตัวบน X ในหมวดหมู่ของ endofunctors แต่มีความคล้ายคลึงกันมากขึ้น
ทั้ง Monad และ Applicative ตรงตามเกณฑ์:
(เช่นในแต่ละวันTree a -> List bแต่ในหมวดหมู่Tree -> List)
Tree -> ListList -> Listคำสั่งใช้ "หมวดหมู่ของ ... " ซึ่งจะกำหนดขอบเขตของคำสั่ง เป็นตัวอย่างที่ Functor หมวดหมู่อธิบายขอบเขตของf * -> g *เช่นAny functor -> Any functorเช่นหรือ Tree * -> List *Tree * -> Tree *
สิ่งที่เป็นคำสั่งเด็ดขาดไม่ได้ระบุอธิบายที่ทุกอย่างจะได้รับอนุญาต
ในกรณีนี้ภายใน functors ที่* -> *รู้จักกันในชื่อไม่ได้ระบุซึ่งหมายความว่าa -> b Anything -> Anything including Anything elseในฐานะที่เป็นจินตนาการของฉันกระโดดไป Int -> String ก็ยังมีInteger -> Maybe Intหรือแม้กระทั่งที่ Maybe Double -> Either String Inta :: Maybe Double; b :: Either String Int
ดังนั้นคำสั่งมารวมกันดังนี้:
:: f a -> g b(เช่นชนิดใด ๆ ที่กำหนดพารามิเตอร์เป็นชนิดที่กำหนดพารามิเตอร์ใด ๆ ):: f a -> f b(กล่าวคือประเภทใด ๆ ที่กำหนดพารามิเตอร์ชนิดที่ปรับพารามิเตอร์เดียวกัน) ... กล่าวว่าแตกต่างกันแล้วพลังของสิ่งก่อสร้างนี้อยู่ที่ไหน? เพื่อชื่นชมการเปลี่ยนแปลงเต็มรูปแบบฉันต้องเห็นว่าภาพวาดทั่วไปของ monoid (วัตถุเดียวที่มีลักษณะเหมือนลูกศรเอกลักษณ์:: single object -> single object) ล้มเหลวในการแสดงให้เห็นว่าฉันได้รับอนุญาตให้ใช้ลูกศรที่กำหนดพารามิเตอร์ด้วยค่า monoid จำนวนเท่าใดก็ได้จากวัตถุประเภทเดียวที่ได้รับอนุญาตใน Monoid endo, ~ identity arrow definition ของความเท่าเทียมกันจะละเว้นค่าประเภทของ functor และทั้งประเภทและค่าของเลเยอร์ "payload" ที่อยู่ด้านในสุด ดังนั้นความเท่าเทียมจะส่งกลับtrueในทุกสถานการณ์ที่ประเภท functorial ตรงกัน (เช่นNothing -> Just * -> Nothingเทียบเท่าJust * -> Just * -> Just *เพราะทั้งคู่Maybe -> Maybe -> Maybe)
แถบด้านข้าง: ~ นอกเป็นแนวความคิด f aแต่ด้านซ้ายสัญลักษณ์มากที่สุดใน นอกจากนี้ยังอธิบายถึงสิ่งที่ "Haskell" อ่านในครั้งแรก (ภาพใหญ่); ดังนั้น Type คือ "ภายนอก" ที่สัมพันธ์กับ Value Type ความสัมพันธ์ระหว่างเลเยอร์ (สายการอ้างอิง) ในการเขียนโปรแกรมไม่ใช่เรื่องง่ายที่จะเกี่ยวข้องในหมวดหมู่ หมวดหมู่ชุดใช้เพื่ออธิบายประเภท (Int, Strings, บางที Int ฯลฯ ) ซึ่งรวมถึงหมวดหมู่ของ Functor (ประเภทพารามิเตอร์) ห่วงโซ่การอ้างอิง: ประเภทของ Functor, ค่าของ Functor (องค์ประกอบของชุดของ Functor นั้น, เช่น Nothing, Just) และในทางกลับกันทุกอย่างอื่นที่แต่ละค่าของ functor ชี้ไป ในหมวดหมู่ความสัมพันธ์นั้นถูกอธิบายแตกต่างกันเช่นreturn :: a -> m aถือเป็นการเปลี่ยนแปลงตามธรรมชาติจาก Functor หนึ่งไปยัง Functor อื่นซึ่งแตกต่างจากสิ่งที่กล่าวถึงในตอนนี้
กลับไปที่เธรดหลักทั้งหมดสำหรับผลิตภัณฑ์เทนเซอร์ที่กำหนดไว้ใด ๆ และค่าที่เป็นกลางคำแถลงนี้อธิบายถึงโครงสร้างการคำนวณที่ทรงพลังอย่างน่าอัศจรรย์ที่เกิดจากโครงสร้างที่ขัดแย้งกัน:
:: List); คงที่foldที่ไม่ได้บอกอะไรเลยเกี่ยวกับเพย์โหลด)ใน Haskell การชี้แจงความเกี่ยวข้องของข้อความเป็นสิ่งสำคัญ อำนาจและความเก่งกาจของโครงสร้างนี้มีอะไรอย่างจะทำอย่างไรกับ monad ต่อ se กล่าวอีกนัยหนึ่งการสร้างไม่ได้ขึ้นอยู่กับสิ่งที่ทำให้ Monad มีความโดดเด่น
เมื่อพยายามที่จะคิดออกว่าจะสร้างรหัสด้วยบริบทที่ใช้ร่วมกันเพื่อสนับสนุนการคำนวณที่ต้องพึ่งพาซึ่งกันและกันหรือไม่กับการคำนวณที่สามารถทำงานแบบขนานได้ข้อความที่น่าอับอายนี้ การใช้งานลูกศรและ Monads แต่เป็นคำอธิบายของพวกเขาเท่ากัน สำหรับการตัดสินใจที่มีอยู่จริง
นี่มักจะเข้าใจผิด คำแถลงยังอธิบายต่อไปว่าjoin :: m (m a) -> m aเป็นผลิตภัณฑ์เทนเซอร์สำหรับเอนโดโฟนตัวเดียว อย่างไรก็ตามมันไม่ได้อธิบายว่าในบริบทของคำแถลง(<*>)นี้ได้รับการเลือกเช่นกันอย่างไร มันเป็นตัวอย่างของหก / ครึ่งโหลอย่างแท้จริง ตรรกะสำหรับการรวมค่านั้นเหมือนกันหมด อินพุตเดียวกันสร้างเอาต์พุตเดียวกันจากแต่ละรายการ (ซึ่งแตกต่างจากผลรวม Sum และ Product สำหรับ Int เพราะจะสร้างผลลัพธ์ที่แตกต่างเมื่อรวม Ints)
ดังนั้นเพื่อสรุป: monoid ในหมวดหมู่ของ endofunctors อธิบาย:
~t :: m * -> m * -> m *
and a neutral value for m *
(<*>)และ(>>=)ให้การเข้าถึงสองmค่าพร้อมกันเพื่อคำนวณค่าส่งคืนเดียว ตรรกะที่ใช้ในการคำนวณค่าส่งคืนเหมือนกันทุกประการ หากไม่ใช่สำหรับรูปร่างที่แตกต่างกันของฟังก์ชั่นที่พวกเขาแปร ( f :: a -> bและk :: a -> m b) และตำแหน่งของพารามิเตอร์ที่มีประเภทการคำนวณแบบส่งคืนเดียวกัน (เช่นa -> b -> bเมื่อเทียบกับb -> a -> bสำหรับแต่ละลำดับ) ฉันสงสัยว่าเราจะได้แปรพารามิเตอร์ตรรกะตรรกะ ผลิตภัณฑ์เทนเซอร์สำหรับนำมาใช้ใหม่ในทั้งสองคำจำกัดความ เป็นแบบฝึกหัดที่จะทำให้ประเด็นลองและนำไปใช้~tและคุณจะจบลงด้วย(<*>)และ(>>=)ขึ้นอยู่กับว่าคุณตัดสินใจกำหนดมันforall a bอย่างไร
หากจุดสุดท้ายของฉันเป็นอย่างน้อยที่สุดจริงแนวคิดมันก็จะอธิบายความแตกต่างที่แม่นยำและเฉพาะการคำนวณระหว่างการใช้งานและ Monad: ฟังก์ชั่นที่พวกเขาแปรปรวน ในคำอื่น ๆ คือความแตกต่างภายนอกในการดำเนินการของการเรียนประเภทเหล่านี้
โดยสรุปจากประสบการณ์ของฉันเองคำพูดที่น่าอับอายของ Mac Lane ได้ให้คำแนะนำ "goto" meme ที่ดีซึ่งเป็นป้ายบอกทางให้ฉันอ้างอิงขณะนำทางผ่านหมวดของฉันเพื่อทำความเข้าใจสำนวนที่ใช้ใน Haskell ให้ดีขึ้น มันประสบความสำเร็จในการบันทึกขอบเขตของความสามารถในการคำนวณที่มีประสิทธิภาพซึ่งทำให้สามารถเข้าถึงได้อย่างมหัศจรรย์ใน Haskell
อย่างไรก็ตามมีประชดในวิธีที่ฉันเข้าใจผิดครั้งแรกการบังคับใช้คำสั่งที่นอกเหนือจาก monad และสิ่งที่ฉันหวังว่าถ่ายทอดที่นี่ ทุกสิ่งที่อธิบายจะกลายเป็นสิ่งที่คล้ายกันระหว่าง Applicative และ Monads (และ Arrows ท่ามกลางคนอื่น ๆ ) สิ่งที่ไม่ได้กล่าวคือความแตกต่างเล็ก ๆ แต่มีประโยชน์อย่างแม่นยำ
- จ
คำตอบที่นี่ทำงานได้อย่างยอดเยี่ยมในการกำหนดทั้ง monoids และ monads อย่างไรก็ตามพวกเขายังดูเหมือนจะไม่ตอบคำถาม:
และในบันทึกย่อที่สำคัญน้อยกว่านี่คือความจริงและถ้าเป็นเช่นนั้นคุณสามารถให้คำอธิบายได้ (หวังว่าจะมีคนที่ไม่เข้าใจประสบการณ์ของ Haskell มาก)
ประเด็นสำคัญของสิ่งที่ขาดหายไปที่นี่คือแนวคิดที่แตกต่างกันของ "monoid" การจำแนกประเภทที่เรียกว่าแม่นยำยิ่งขึ้น - หนึ่งของ monoid ในหมวดหมู่ monoidal หนังสือของ Sadly Mac Lane นั้นทำให้เกิดความสับสน :
ทั้งหมดบอกว่า monad ใน
Xเป็นเพียง monoid ในหมวดหมู่ของ endofunctors ของXด้วยผลิตภัณฑ์ที่×ถูกแทนที่ด้วยองค์ประกอบของ endofunctors และหน่วยที่กำหนดโดย endofunctor ตัวตน
ทำไมถึงสับสน? เพราะมันไม่ได้กำหนดว่าอะไรคือ "หนังสือในหมวดหมู่ของ endofunctors ว่า" Xของ แต่ประโยคนี้แสดงให้เห็นว่ามีการสร้าง monoid ภายในชุดของ endofunctors ทั้งหมดพร้อมกับการจัดองค์ประกอบของ functor เป็นการดำเนินการแบบไบนารี่ ซึ่งทำงานได้ดีอย่างสมบูรณ์แบบและเปลี่ยนเป็น monoid ส่วนย่อยของ endofunctors ใด ๆ ที่มี functor ตัวตนและถูกปิดภายใต้องค์ประกอบ functor
แต่นี่ไม่ใช่การตีความที่ถูกต้องซึ่งหนังสือไม่สามารถอธิบายได้อย่างชัดเจนในขั้นตอนนั้น Monad fเป็นendofunctor คงที่ไม่ใช่เซตย่อยของ endofunctors ที่ปิดภายใต้การจัดองค์ประกอบ การสร้างร่วมกันคือการใช้fเพื่อสร้างหนังสือโดยการตั้งค่าของทุกkองค์ประกอบเท่าf^k = f(f(...))ของfด้วยตัวเองรวมทั้งสอดคล้องกับตัวตนที่k=0 f^0 = idและตอนนี้ชุดSของพลังทั้งหมดเหล่านี้สำหรับทุกคนk>=0ย่อมเป็น monoid "กับผลิตภัณฑ์×แทนที่ด้วยองค์ประกอบของ endofunctors และหน่วยที่กำหนดโดย endofunctor เอกลักษณ์"
และยัง:
Sสามารถกำหนดสำหรับ functor ใด ๆfหรือแม้กระทั่งตัวอักษรสำหรับการใด ๆ Xด้วยตนเองแผนที่ของ fมันเป็นหนังสือที่สร้างขึ้นโดยSกำหนดโดยองค์ประกอบ functor และ functor เอกลักษณ์ไม่มีอะไรเกี่ยวข้องกับfการเป็นหรือไม่เป็น monadและเพื่อให้สิ่งที่มากขึ้นทำให้เกิดความสับสนความหมายของ "หนังสือในหมวดหมู่ monoidal" มาต่อมาในหนังสือที่คุณสามารถดูจากตารางของเนื้อหา และยังเข้าใจความคิดนี้เป็นสิ่งสำคัญอย่างยิ่งที่จะเข้าใจการเชื่อมต่อกับพระ
ไปบทที่เจ็ดใน Monoids (ที่มาช้ากว่าบทที่หกบน Monads) เราจะพบความหมายของสิ่งที่เรียกว่าหมวดหมู่ monoidal เข้มงวดเป็นสาม(B, *, e)ที่Bเป็นหมวดหมู่, bifunctor (functor ที่เกี่ยวกับส่วนประกอบแต่ละคนมีองค์ประกอบอื่น ๆ คงที่ ) และเป็นวัตถุหน่วยในการตอบสนองความสัมพันธ์และกฎหมายหน่วย:*: B x B-> BeB
(a * b) * c = a * (b * c)
a * e = e * a = a
สำหรับวัตถุใด ๆa,b,cของBและอัตลักษณ์เดียวกัน morphisms ใด ๆa,b,cกับการeแทนที่ด้วยการซึ่มส์ตัวตนของid_e eขณะนี้เป็นคำแนะนำให้สังเกตว่าในกรณีที่เราสนใจซึ่งBเป็นประเภทของ endofunctors ของXกับการเปลี่ยนแปลงตามธรรมชาติเป็น morphisms *องค์ประกอบ functor และefunctor ตัวตนกฎหมายเหล่านี้มีความพึงพอใจทั้งหมดที่สามารถตรวจสอบได้โดยตรง
สิ่งที่เกิดขึ้นภายหลังในหนังสือเล่มนี้คือคำจำกัดความของหมวดหมู่ "ผ่อนคลาย" ซึ่งมีเพียงโมดูโล่ที่มีการเปลี่ยนแปลงตามธรรมชาติบางอย่างที่น่าพอใจซึ่งเรียกว่าความสัมพันธ์ที่เชื่อมโยงกันซึ่งไม่สำคัญสำหรับกรณีของเราในหมวดหมู่ endofunctor
สุดท้ายในส่วนที่ 3 "Monoids" ของบทที่ VII คำจำกัดความที่แท้จริงได้รับ:
monoid
cในประเภท monoidal(B, *, e)เป็นวัตถุที่Bมีลูกศรสองอัน (morphisms)
mu: c * c -> c
nu: e -> c
ทำให้ 3 แผนภาพสับเปลี่ยน จำได้ว่าในกรณีของเราเหล่านี้เป็น morphisms ในหมวดหมู่ของ endofunctors ซึ่งเป็นการเปลี่ยนแปลงตามธรรมชาติที่สอดคล้องกับแม่นยำjoinและreturnสำหรับ monad การเชื่อมต่อจะชัดเจนยิ่งขึ้นเมื่อเราทำให้การจัดองค์ประกอบ*ชัดเจนมากขึ้นแทนที่c * cด้วยmonad ของเราอยู่c^2ที่ไหนc
ในที่สุดสังเกตว่า 3 ไดอะแกรมสลับสับเปลี่ยน (ในคำจำกัดความของ monoid ในหมวดหมู่ monoidal) เขียนสำหรับหมวดหมู่ monoidal ทั่วไป (ไม่เข้มงวด) ในขณะที่ในกรณีของเราการเปลี่ยนแปลงตามธรรมชาติทั้งหมดที่เกิดขึ้นเป็นส่วนหนึ่งของหมวดหมู่ monoidal นั่นจะทำให้ไดอะแกรมเหมือนกับที่อยู่ในคำจำกัดความของ monad ทำให้การติดต่อทางจดหมายเสร็จสมบูรณ์
ในการสรุป monad ใด ๆ ที่เป็นโดยความหมาย endofunctor ดังนั้นวัตถุที่อยู่ในหมวดหมู่ของ endofunctors ที่ที่เอกjoinและreturnผู้ประกอบการตอบสนองความหมายของหนังสือในเฉพาะ (เข้มงวด) หมวด ในทางกลับกัน monoid ใด ๆ ในหมวดหมู่ monoidal ของ endofunctors โดยนิยามสาม(c, mu, nu)ประกอบด้วยวัตถุและลูกศรสองลูกเช่นการเปลี่ยนแปลงตามธรรมชาติในกรณีของเราพอใจกฎหมายเดียวกันกับ monad
ในที่สุดให้สังเกตความแตกต่างที่สำคัญระหว่าง monoids (แบบคลาสสิก) และ monoids ทั่วไปในหมวดหมู่ monoidal ทั้งสองลูกศรmuและnuข้างต้นไม่ได้อีกต่อไปดำเนินการทวิภาคและหน่วยในชุด แต่คุณมีหนึ่ง cendofunctor องค์ประกอบนักแต่งเพลง*และนักแสดงตัวตนเพียงอย่างเดียวไม่ได้จัดเตรียมโครงสร้างที่สมบูรณ์ที่จำเป็นสำหรับ monad แม้จะมีคำพูดที่สับสนในหนังสือ
อีกวิธีหนึ่งที่จะเปรียบเทียบกับหนังสือมาตรฐานCของทุกแผนที่ตนเองของชุดAที่ดำเนินการทวิภาคเป็นองค์ประกอบที่สามารถมองเห็นไปยังแผนที่ผลิตภัณฑ์คาร์ทีเซียนมาตรฐานเข้าไปC x C Cผ่านไปยังหมวดหมู่ monoid เรากำลังเปลี่ยนผลิตภัณฑ์ cartesian xด้วยองค์ประกอบ functor *และการดำเนินการแบบไบนารีจะถูกแทนที่ด้วยการแปลงตามธรรมชาติmuจาก
c * cไปcเป็นนั่นคือชุดของjoinผู้ประกอบการ
join: c(c(T))->c(T)
สำหรับวัตถุทุกTชนิด (พิมพ์โปรแกรม) และองค์ประกอบประจำตัวใน monoids แบบคลาสสิกซึ่งสามารถระบุด้วยภาพของแผนที่จากจุดหนึ่งจุดคงที่ได้รับการแทนที่ด้วยคอลเลกชันของreturnผู้ประกอบการ
return: T->c(T)
แต่ตอนนี้ไม่มีผลิตภัณฑ์คาร์ทีเซียนอีกต่อไปดังนั้นจึงไม่มีคู่ขององค์ประกอบและจึงไม่มีการดำเนินการแบบไบนารี