Biapplicative and Bimonad?

末鹿安然 提交于 2019-12-18 10:23:00

问题


Haskell's Data.Bifunctor is basically:

class Bifunctor f where
  bimap :: (a -> c) -> (b -> d) -> f a b -> f c d 

I could find a Biapply as well. My question is, why isn't there a complete bi-hierarchy (bierarchy?) like:

class Bifunctor f => Biapplicative f where
  bipure :: a -> b -> f a b
  biap :: f (a -> b) (c -> d) -> f a c -> f b d 

class Biapplicative m => Bimonad m where
  bibind :: m a b -> (a -> b -> m c d) -> m c d

  bireturn :: a -> b -> m a b
  bireturn = bipure

bilift :: Biapplicative f => (a -> b) -> (c -> d) -> f a c -> f b d
bilift f g = biap $ bipure f g 

bilift2 :: Biapplicative f => (a -> b -> c) -> (x -> y -> z) -> f a x -> f b y -> f c z
bilift2 f g = biap . biap (bipure f g)

Pair is an instance of these:

instance Bifunctor (,) where
  bimap f g (x,y) = (f x, g y)

instance Biapplicative (,) where
  bipure x y = (x,y)
  biap (f,g) (x,y) = (f x, g y)

instance Bimonad (,) where
  bibind (x,y) f = f x y

And types like...

data Maybe2 a b = Fst a | Snd b | None
--or 
data Or a b = Both a b | This a | That b | Nope

...would IMO have instances as well.

Are there not enough matching types? Or is something concerning my code deeply flawed?


回答1:


A monad in category theory is an endofunctor, i.e. a functor where the domain and codomain is the same category. But a Bifunctor is a functor from the product category Hask x Hask to Hask. But we could try to find out what a monad in the Hask x Hask category looks like. It is a category where objects are pairs of types, i.e. (a, b), and arrows are pairs of functions, i.e. an arrow from (a, b) to (c, d) has type (a -> c, b -> d). An endofunctor in this category maps pairs of types to pairs of types, i.e. (a, b) to (l a b, r a b), and pairs of arrows to pairs of arrows, i.e.

(a -> c, b -> d) -> (l a b -> l c d, r a b -> r c d)

If you split this map function in 2, you'll see that an endofunctor in Hask x Hask is the same as two Bifunctors, l and r.

Now for the monad: return and join are arrows, so in this case both are 2 functions. return is an arrow from (a, b) to (l a b, r a b), and join is an arrow from (l (l a b) (r a b), r (l a b) (r a b)) to (l a b, r a b). This is what it looks like:

class (Bifunctor l, Bifunctor r) => Bimonad l r where
  bireturn :: (a -> l a b, b -> r a b)
  bijoin :: (l (l a b) (r a b) -> l a b, r (l a b) (r a b) -> r a b)

Or separated out:

class (Bifunctor l, Bifunctor r) => Bimonad l r where
  bireturnl :: a -> l a b
  bireturnr :: b -> r a b
  bijoinl :: l (l a b) (r a b) -> l a b
  bijoinr :: r (l a b) (r a b) -> r a b

And similar to m >>= f = join (fmap f m) we can define:

  bibindl :: l a b -> (a -> l c d) -> (b -> r c d) -> l c d
  bibindl lab l r = bijoinl (bimap l r lab)
  bibindr :: r a b -> (a -> l c d) -> (b -> r c d) -> r c d
  bibindr rab l r = bijoinr (bimap l r rab)

Relative monads

Recently, relative monads have been developed. A relative monad doesn't need to be an endofunctor! If we translate from the paper to Bifunctors in Haskell, you get:

class RelativeBimonad j m where
  bireturn :: j a b -> m a b
  bibind :: m a b -> (j a b -> m c d) -> m c d

Which defines a monad relative to the bifunctor j. If you pick j to be (,) you get your definition.

The laws are the same as the monad laws:

bireturn jab `bibind` k = k jab
m `bibind` bireturn = m
m `bibind` (\jab -> k jab `bibind` h) = (m `bibind` k) `bibind` h

The first law prevents Maybe2 from being an instance, because bibind has to be able to extract both values from the result of bireturn.



来源:https://stackoverflow.com/questions/13556314/biapplicative-and-bimonad

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!