【问题标题】:Biapplicative and Bimonad?Biapplicative 和 Bimonad?
【发布时间】:2012-11-25 22:38:44
【问题描述】:

Haskell 的Data.Bifunctor 基本上是:

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

我也可以找到Biapply。我的问题是,为什么没有完整的双层次结构(bierarchy?),例如:

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 是这些的一个实例:

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

类型如...

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

...IMO 也会有实例。

没有足够的匹配类型吗?还是我的代码存在严重缺陷?

【问题讨论】:

  • 您如何为Maybe2 a b 定义bipure? Fst 和 Snd 都不是规范的,剩下的 None 几乎没有用处。我认为这些类的大多数重要候选类型都有类似的问题,但这只是一个猜测。至少Or 看起来是合理的。好问题。
  • 另外,你如何定义bijoin?
  • 从实际的角度来看,我想说这些类型类没有被使用的原因是它们很少有有趣的实例。考虑Bifunctor 有多少实例。那么Biapplicative 或Bimonad 会更少(可能为0)。除此之外,这当然是一个有趣的问题。您是否尝试过构建这些建议的类型类的一些完整实例?
  • 定义Bifunctor 的bifunctors 库确实有一个Biapplicative 类,但它没有定义bipure 和<<*>> 应该遵守的任何法律,类似于定义的法律对于pure 和<*>。它定义了一些实例:您的(,),一个用于Const,以及一些与它们大致同构的类型。更高元组的实例任意(?)要求产品中最左边的类型是幺半群,以便它们可以简单地通过<<*>> 累加。
  • (应用函子是强松散幺半函子这一事实可能表明对 n>2 元组的幺半群限制不是任意的,但我不知道“强松散幺半双函子”是否是东西。)

标签: haskell monads


【解决方案1】:

范畴论中的单子是一个内函子,即域和余域是同一类别的函子。但是Bifunctor 是从产品类别Hask x Hask 到Hask 的函子。但我们可以尝试找出 Hask x Hask 类别中的 monad 是什么样的。它是一个类别,其中对象是成对的类型,即(a, b),箭头是成对的函数,即从(a, b) 到(c, d) 的箭头具有(a -> c, b -> d) 类型。此类别中的内函子将类型对映射到类型对,即(a, b) 到 (l a b, r a b),并将箭头对映射到箭头对,即

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

如果将此映射函数拆分为 2,您将看到 Hask x Hask 中的一个内函子与两个 Bifunctors、l 和 r 相同。

现在是 monad:return 和 join 是箭头,所以在这种情况下,它们都是 2 个函数。 return 是从(a, b) 到(l a b, r a b) 的箭头,join 是从(l (l a b) (r a b), r (l a b) (r a b)) 到(l a b, r a b) 的箭头。这是它的样子:

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)

或分离出来:

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

和m >>= f = join (fmap f m)类似,我们可以定义:

  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。相对单子不需要是内函子!如果我们将论文翻译成 Haskell 中的Bifunctors,您会得到:

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

它定义了一个相对于双函子j 的单子。如果您选择 j 为 (,),您将得到您的定义。

定律与单子定律相同:

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

第一定律阻止Maybe2 成为实例,因为bibind 必须能够从bireturn 的结果中提取两个值。

【讨论】:

  • 附言。我认为您的Biapplicative 课程是正确的。双应用函子似乎与从Hask x Hask 到Hask 的单曲面函子相匹配。
  • 我不明白为什么有两种不同的类型l 和r。让它们相同不是更容易吗?说class (Bifunctor m) => Bimonad m 和instance Bimonad Either where bireturnl = Left; bireturnr = Right; bijoin = either id id (bibind = either)?
  • 你可以这样做,但是你没有范畴论意义上的单子:en.wikipedia.org/wiki/Monad_(category_theory)
  • 如果l ~ r,是bijoinl = bijoinr?另外,是bireturnl = bireturnr? (大概不是)
  • @SjoerdVisscher 我不太明白为什么Bimonad l r 的超类约束是(Bifunctor l, Bifunctor r) 而不是Biendofunctor l r,以及你之前描述的态射映射bifmap :: Biendofunctor l r => (a -> b, c -> d) -> (l a c -> l b d, r a c -> r b d)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-25
  • 2011-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多