ฉันต้องการเสนอวิธีการที่เป็นระบบมากขึ้นในการตอบคำถามนี้และเพื่อแสดงตัวอย่างที่ไม่ใช้เทคนิคพิเศษใด ๆ เช่นค่า "ล่าง" หรือประเภทข้อมูลที่ไม่มีที่สิ้นสุดหรืออะไรแบบนั้น
ตัวสร้างประเภทเมื่อไม่สามารถมีอินสแตนซ์ของคลาสชนิดได้เมื่อใด
โดยทั่วไปมีสองเหตุผลว่าทำไมตัวสร้างประเภทไม่สามารถมีอินสแตนซ์ของคลาสชนิดที่แน่นอน:
- ไม่สามารถใช้ลายเซ็นประเภทของวิธีการที่จำเป็นจากคลาสประเภท
- สามารถใช้ลายเซ็นประเภท แต่ไม่สามารถปฏิบัติตามกฎหมายที่ต้องการได้
ตัวอย่างของชนิดแรกนั้นง่ายกว่าของชนิดที่สองเพราะสำหรับชนิดแรกเราเพียงแค่ต้องตรวจสอบว่าสามารถใช้ฟังก์ชันที่มีลายเซ็นประเภทที่กำหนดหรือไม่สำหรับประเภทที่สองเราต้องพิสูจน์ว่าไม่มีการใช้งาน อาจเป็นไปตามกฎหมาย
ตัวอย่างที่เฉพาะเจาะจง
นี่คือ contrafunctor ไม่ใช่ functor ที่เกี่ยวกับพารามิเตอร์ type aเนื่องจากaอยู่ในตำแหน่งที่แตกต่างกัน (a -> b) -> F z a -> F z bมันเป็นไปไม่ได้ที่จะใช้ฟังก์ชั่นที่มีลายเซ็นประเภท
คอนสตรัคเตอร์ประเภทที่ไม่ใช่ functor ที่ชอบด้วยกฎหมายถึงแม้ว่าลายเซ็นต์ประเภทของfmapสามารถนำไปใช้ได้:
data Q a = Q(a -> Int, a)
fmap :: (a -> b) -> Q a -> Q b
fmap f (Q(g, x)) = Q(\_ -> g x, f x) -- this fails the functor laws!
ตัวอย่างที่น่าสงสัยของตัวอย่างนี้คือเราสามารถใช้งานfmapประเภทที่ถูกต้องได้แม้ว่าFจะไม่สามารถเป็นนักแสดงเพราะใช้aในตำแหน่งที่แตกต่างกัน ดังนั้นการดำเนินการตามที่fmapแสดงด้านบนนี้ทำให้เข้าใจผิด - แม้ว่าจะมีลายเซ็นประเภทที่ถูกต้อง (ฉันเชื่อว่านี่เป็นเพียงการดำเนินการที่เป็นไปได้ของลายเซ็นประเภทนั้น) กฎหมาย functor ไม่พอใจ ยกตัวอย่างเช่นfmap id≠ idเพราะlet (Q(f,_)) = fmap id (Q(read,"123")) in f "456"เป็น123แต่เป็นlet (Q(f,_)) = id (Q(read,"123")) in f "456"456
ในความเป็นจริงFมันเป็นเพียงนักพรต - มันไม่ใช่ functor หรือ contrafunctor
นักกฎหมายที่ไม่ได้ใช้งานเพราะไม่สามารถใช้ลายเซ็นประเภทของpure: นำนักเขียน monad (a, w)และลบข้อ จำกัด ที่wควรจะเป็น monoid แล้วมันเป็นไปไม่ได้ที่จะสร้างค่าของชนิดออกจาก(a, w)a
นักเขียนที่ไม่ได้สมัครเนื่องจากลายเซ็นประเภทของ<*>ไม่สามารถใช้งานได้: data F a = Either (Int -> a) (String -> a).
functor ที่ไม่ถูกต้องตามกฎหมายถึงแม้ว่าวิธีการเรียนประเภทสามารถนำมาใช้:
data P a = P ((a -> Int) -> Maybe a)
ตัวสร้างประเภทPเป็น functor เนื่องจากใช้aเฉพาะในตำแหน่ง covariant
instance Functor P where
fmap :: (a -> b) -> P a -> P b
fmap fab (P pa) = P (\q -> fmap fab $ pa (q . fab))
การนำไปใช้ที่เป็นไปได้ของลายเซ็นประเภท<*>คือฟังก์ชันที่ส่งคืนเสมอNothing:
(<*>) :: P (a -> b) -> P a -> P b
(P pfab) <*> (P pa) = \_ -> Nothing -- fails the laws!
แต่การดำเนินการนี้ไม่เป็นไปตามกฎหมายว่าด้วยตัวตนของผู้ปฏิบัติงาน
- นักแสดงที่
Applicativeไม่ได้เป็นMonadเพราะลายเซ็นประเภทของbindไม่สามารถใช้งานได้
ฉันไม่รู้ตัวอย่างเช่น!
- นักแสดงที่
Applicativeไม่ได้เป็นMonadเพราะกฎหมายไม่สามารถสร้างความพึงพอใจแม้ว่าลายเซ็นประเภทของbindสามารถนำมาใช้
ตัวอย่างนี้ได้สร้างการสนทนาค่อนข้างน้อยดังนั้นจึงปลอดภัยที่จะกล่าวว่าการพิสูจน์ตัวอย่างนี้ถูกต้องไม่ใช่เรื่องง่าย แต่หลายคนได้ตรวจสอบเรื่องนี้อย่างอิสระด้วยวิธีการที่แตกต่างกัน ดูIs` data PoE a = Empty | จับคู่ aa` a monad ไหม? สำหรับการสนทนาเพิ่มเติม
data B a = Maybe (a, a)
deriving Functor
instance Applicative B where
pure x = Just (x, x)
b1 <*> b2 = case (b1, b2) of
(Just (x1, y1), Just (x2, y2)) -> Just((x1, x2), (y1, y2))
_ -> Nothing
ค่อนข้างยุ่งยากที่จะพิสูจน์ว่าไม่มีMonadตัวอย่างที่ชอบด้วยกฎหมาย เหตุผลในการทำงานที่ไม่เป็นเอกคือว่าไม่มีวิธีธรรมชาติของการดำเนินการbindเมื่อมีฟังก์ชั่นf :: a -> B bจะกลับมาNothingหรือค่าที่แตกต่างกันของJusta
บางทีมันก็เป็นที่ชัดเจนที่จะต้องพิจารณาMaybe (a, a, a)ซึ่งยังไม่ monad และจะพยายามดำเนินjoinการที่ joinหนึ่งจะพบว่าไม่มีวิธีการที่เหมาะสมในการดำเนินการอย่างสังหรณ์ใจ
join :: Maybe (Maybe (a, a, a), Maybe (a, a, a), Maybe (a, a, a)) -> Maybe (a, a, a)
join Nothing = Nothing
join Just (Nothing, Just (x1,x2,x3), Just (y1,y2,y3)) = ???
join Just (Just (x1,x2,x3), Nothing, Just (y1,y2,y3)) = ???
-- etc.
ในกรณีที่ระบุโดย???ดูเหมือนว่าชัดเจนว่าเราไม่สามารถผลิตJust (z1, z2, z3)ในลักษณะที่เหมาะสมและสมมาตรใด ๆ aหกออกมาจากค่าที่แตกต่างจากประเภท แน่นอนว่าเราสามารถเลือกเซตย่อยทั้งหกของค่านิยมเหล่านี้ได้ตัวอย่างเช่นใช้เวลาไม่ว่างก่อนเสมอMaybe- แต่สิ่งนี้จะไม่เป็นไปตามกฎหมายของ monad การกลับมาNothingจะไม่เป็นไปตามกฎหมาย
- โครงสร้างข้อมูลที่มีลักษณะคล้ายต้นไม้ที่ไม่ได้เป็น monadแม้ว่าจะมีการเชื่อมโยงกัน
bindแต่ก็ไม่สามารถใช้กฎหมายตัวตนได้
monad เหมือนต้นไม้ทั่วไป (หรือ "ต้นไม้ที่มีสาขาที่มีรูปทรง functor") ถูกกำหนดเป็น
data Tr f a = Leaf a | Branch (f (Tr f a))
นี่คือ monad ฟรีผ่าน ffunctor รูปร่างของข้อมูลเป็นต้นไม้ที่แต่ละจุดสาขาเป็น "functor-ful" ของ subtrees type f a = (a, a)ต้นไม้ไบนารีมาตรฐานจะได้รับกับ
ถ้าเราปรับเปลี่ยนโครงสร้างข้อมูลนี้โดยการยังใบในรูปของ functor ที่fเราได้รับสิ่งที่ผมเรียก "semimonad" - มันมีbindที่ตรงกับ naturality และกฎหมายที่เชื่อมโยงกัน แต่ของpureวิธีการล้มเหลวหนึ่งในกฎหมายเอกลักษณ์ "Semimonads เป็นกลุ่มย่อยในหมวดหมู่ของ endofunctors ปัญหาคืออะไร" Bindนี่คือระดับประเภท
เพื่อความเรียบง่ายฉันกำหนดjoinวิธีการแทนbind:
data Trs f a = Leaf (f a) | Branch (f (Trs f a))
join :: Trs f (Trs f a) -> Trs f a
join (Leaf ftrs) = Branch ftrs
join (Branch ftrstrs) = Branch (fmap @f join ftrstrs)
การปลูกถ่ายอวัยวะสาขาเป็นมาตรฐาน Branchแต่การปลูกถ่ายอวัยวะใบที่ไม่ได้มาตรฐานและผลิต นี่ไม่ใช่ปัญหาของกฎหมายการเชื่อมโยง แต่เป็นการทำลายหนึ่งในตัวตนของกฎหมาย
พหุนามประเภทใดมีอินสแตนซ์ monad
ทั้ง functors Maybe (a, a)และMaybe (a, a, a)สามารถให้ถูกต้องตามกฎหมายเช่นแม้ว่าพวกเขาจะเห็นได้ชัดว่าMonadApplicative
ฟังก์ชั่นเหล่านี้ไม่มีลูกเล่น - ไม่Voidหรือbottomที่ใดก็ได้ไม่มีความขี้เกียจ / ความเข้มงวดไม่มีโครงสร้างที่ไม่มีที่สิ้นสุดและไม่มีข้อ จำกัด ประเภทคลาส Applicativeเช่นเป็นมาตรฐานสมบูรณ์ ฟังก์ชั่นreturnและbindสามารถนำมาใช้สำหรับฟังก์ชั่นเหล่านี้ แต่จะไม่เป็นไปตามกฎหมายของ monad กล่าวอีกนัยหนึ่งฟังก์ชั่นเหล่านี้ไม่ใช่ monads เพราะโครงสร้างที่เฉพาะเจาะจงหายไป (แต่มันไม่ง่ายที่จะเข้าใจสิ่งที่ขาดหายไป) ตัวอย่างเช่นการเปลี่ยนแปลงเล็กน้อยใน functor สามารถทำให้มันกลายเป็น monad: data Maybe a = Nothing | Just aเป็น monad นักแสดงที่คล้ายกันอีกคนdata P12 a = Either a (a, a)ก็เป็นพระ
การก่อสร้างสำหรับพระพหุนาม
โดยทั่วไปแล้วนี่คือสิ่งปลูกสร้างบางอย่างที่สร้างMonadประเภทพหุนามที่ชอบด้วยกฎหมาย ในสิ่งปลูกสร้างเหล่านี้ทั้งหมดMคือ monad:
type M a = Either c (w, a)อยู่ที่ไหนwmonoid
type M a = m (Either c (w, a))อยู่ที่ไหนmmonad และwเป็น monoid ใด ๆ
type M a = (m1 a, m2 a)ที่ไหนm1และm2เป็นพระใด ๆ
type M a = Either a (m a)ที่ไหนmmonad
การก่อสร้างแรกคือการก่อสร้างที่สองคือWriterT w (Either c) WriterT w (EitherT c m)การสร้างที่สามเป็นผลิตภัณฑ์ที่มีส่วนประกอบของ monads: pure @Mถูกกำหนดให้เป็นผลิตภัณฑ์ที่ส่วนประกอบของpure @m1และpure @m2และjoin @Mถูกกำหนดโดยการละเว้นข้อมูลข้ามผลิตภัณฑ์ (เช่นm1 (m1 a, m2 a)แมปไปm1 (m1 a)โดยการละเว้นส่วนที่สองของ tuple):
join :: (m1 (m1 a, m2 a), m2 (m1 a, m2 a)) -> (m1 a, m2 a)
join (m1x, m2x) = (join @m1 (fmap fst m1x), join @m2 (fmap snd m2x))
การก่อสร้างที่สี่หมายถึง
data M m a = Either a (m a)
instance Monad m => Monad M m where
pure x = Left x
join :: Either (M m a) (m (M m a)) -> M m a
join (Left mma) = mma
join (Right me) = Right $ join @m $ fmap @m squash me where
squash :: M m a -> m a
squash (Left x) = pure @m x
squash (Right ma) = ma
ฉันตรวจสอบแล้วว่าสิ่งปลูกสร้างทั้งสี่นี้สร้างพระที่ชอบด้วยกฎหมาย
ฉันคาดเดาว่าไม่มีสิ่งปลูกสร้างอื่นสำหรับพระพหุนาม ตัวอย่างเช่น functor Maybe (Either (a, a) (a, a, a, a))ไม่ได้รับจากสิ่งปลูกสร้างเหล่านี้และดังนั้นจึงไม่ใช่ monadic แต่Either (a, a) (a, a, a)เป็นเอกเพราะมันเป็น isomorphic กับผลิตภัณฑ์ของสาม monads a, และa Maybe aนอกจากนี้ยังEither (a,a) (a,a,a,a)เป็นเอกเพราะมันเป็น isomorphic กับผลิตภัณฑ์ของและaEither a (a, a, a)
สี่การก่อสร้างที่แสดงข้างต้นจะช่วยให้เราเพื่อให้ได้ผลรวมของจำนวนของผลิตภัณฑ์ของจำนวนใด ๆa's เช่นEither (Either (a, a) (a, a, a, a)) (a, a, a, a, a))และอื่น ๆ ตัวสร้างประเภทดังกล่าวทั้งหมดจะมีMonadอินสแตนซ์(อย่างน้อยหนึ่ง)
แน่นอนว่ายังคงต้องมีกรณีการใช้งานใดบ้างสำหรับพระสงฆ์เหล่านี้ ปัญหาอีกประการคือMonadอินสแตนซ์ที่ได้จากการสร้าง 1-4 นั้นโดยทั่วไปไม่ซ้ำกัน ตัวอย่างเช่นพิมพ์สร้างtype F a = Either a (a, a)จะได้รับMonadเช่นในสองวิธีโดยการก่อสร้าง 4 ใช้ monad (a, a)และโดยการก่อสร้าง 3 Either a (a, a) = (a, Maybe a)ใช้ประเภทมอร์ฟ การค้นหากรณีใช้งานสำหรับการนำไปใช้งานเหล่านี้ไม่ชัดเจนในทันที
คำถามยังคงอยู่ - เนื่องจากประเภทข้อมูลพหุนามโดยพลการวิธีการรับรู้ว่ามันมีMonadตัวอย่าง ฉันไม่รู้วิธีที่จะพิสูจน์ว่าไม่มีสิ่งปลูกสร้างอื่นสำหรับพระพหุนาม ฉันไม่คิดว่ามีทฤษฎีใดที่จะตอบคำถามนี้ได้
* -> *) ซึ่งไม่มีความเหมาะสมfmap?