ฉันต้องการเสนอวิธีการที่เป็นระบบมากขึ้นในการตอบคำถามนี้และเพื่อแสดงตัวอย่างที่ไม่ใช้เทคนิคพิเศษใด ๆ เช่นค่า "ล่าง" หรือประเภทข้อมูลที่ไม่มีที่สิ้นสุดหรืออะไรแบบนั้น
ตัวสร้างประเภทเมื่อไม่สามารถมีอินสแตนซ์ของคลาสชนิดได้เมื่อใด
โดยทั่วไปมีสองเหตุผลว่าทำไมตัวสร้างประเภทไม่สามารถมีอินสแตนซ์ของคลาสชนิดที่แน่นอน:
- ไม่สามารถใช้ลายเซ็นประเภทของวิธีการที่จำเป็นจากคลาสประเภท
- สามารถใช้ลายเซ็นประเภท แต่ไม่สามารถปฏิบัติตามกฎหมายที่ต้องการได้
ตัวอย่างของชนิดแรกนั้นง่ายกว่าของชนิดที่สองเพราะสำหรับชนิดแรกเราเพียงแค่ต้องตรวจสอบว่าสามารถใช้ฟังก์ชันที่มีลายเซ็นประเภทที่กำหนดหรือไม่สำหรับประเภทที่สองเราต้องพิสูจน์ว่าไม่มีการใช้งาน อาจเป็นไปตามกฎหมาย
ตัวอย่างที่เฉพาะเจาะจง
นี่คือ 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
หรือค่าที่แตกต่างกันของJust
a
บางทีมันก็เป็นที่ชัดเจนที่จะต้องพิจารณา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 ฟรีผ่าน f
functor รูปร่างของข้อมูลเป็นต้นไม้ที่แต่ละจุดสาขาเป็น "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)
สามารถให้ถูกต้องตามกฎหมายเช่นแม้ว่าพวกเขาจะเห็นได้ชัดว่าMonad
Applicative
ฟังก์ชั่นเหล่านี้ไม่มีลูกเล่น - ไม่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)
อยู่ที่ไหนw
monoid
type M a = m (Either c (w, a))
อยู่ที่ไหนm
monad และw
เป็น monoid ใด ๆ
type M a = (m1 a, m2 a)
ที่ไหนm1
และm2
เป็นพระใด ๆ
type M a = Either a (m a)
ที่ไหนm
monad
การก่อสร้างแรกคือการก่อสร้างที่สองคือ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 กับผลิตภัณฑ์ของและa
Either 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
?