Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Biapplicative and Bimonad?

Tags:

haskell

monads

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?

like image 664
Landei Avatar asked Nov 25 '12 22:11

Landei


1 Answers

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.

like image 93
Sjoerd Visscher Avatar answered Sep 20 '22 12:09

Sjoerd Visscher