【问题标题】:What is this thing similar to KleisliFunctor?这个和 KleisliFunctor 类似的东西是什么?
【发布时间】:2017-04-04 14:47:07
【问题描述】:

这是我们如何定义KleisliFunctor

class (Monad m, Functor f) => KleisliFunctor m f where
  kmap :: (a -> m b) -> f a -> f b
  kmap f = kjoin . fmap f

  kjoin :: f (m a) -> f a
  kjoin = kmap id

这种类型是否分类

class (Functor f, Monad m) => Absorb f m where
  (>>~) :: f a -> (a -> m b) -> m b
  a >>~ f = ajoin $ fmap f a

  ajoin :: f (m a) -> m a
  ajoin a = a >>~ id

适合范畴论吗?有哪些法律规定?他们是

a >>~ g . f     === fmap f a >>~ g
a >>~ (f >=> g) === a >>~ f >>= g

?

【问题讨论】:

  • 您是否有一些特定的示例类型允许Absorb 实例,但没有足够强大的标准实例来实现(>>~)ajoin
  • @leftaroundabout,我需要Absorb 来实现广义的单子折叠,允许在f 函子中保留一个累加器,但在m 单子中返回结果。参见例如this.

标签: haskell monads typeclass category-theory


【解决方案1】:

这是一个推测性的答案。谨慎行事。

让我们首先考虑KleisliFunctor,重点关注类绑定箭头映射:

class (Monad m, Functor f) => KleisliFunctor m f where
  kmap :: (a -> m b) -> f a -> f b

要使其真正成为从mHask 的 Kleisli 类别的函子,kmap 必须遵循相关的函子定律:

-- Mapping the identity gives identity (in the other category).
kmap return = id
-- Mapping a composed arrow gives a composed arrow (in the other category).
kmap (g <=< f) = kmap g . kmap f

涉及两个Functors 的事实使事情有点不寻常,但并非不合理——例如,法律确实适用于mapMaybe,这是KleisliFunctor 帖子提到的第一个具体示例.

至于Absorb,为了清楚起见,我将类似于bind的方法翻转一下:

class (Functor f, Monad m) => Absorb f m where
  (~<<) :: (a -> m b) -> f a -> m b

如果我们正在寻找类似于KleisliFunctor 的东西,那么立即出现的一个问题是哪个类别将具有f a -&gt; m b 类型的函数作为箭头。它当然不能是 Hask,因为它的身份(f a -&gt; m a 类型)不能是 id。我们不仅要弄清楚身份,还要弄清楚组成。对于与Monad 不完全不同的东西...

idAbsorb :: f a -> m a
compAbsorb :: (f b -> m c) -> (f a -> m b) -> (f a -> m c)

...我现在唯一能想到的可能是有一个单子态射为idAbsorb 并在相反方向使用第二个单子态射(即从mf),这样compAbsorb 可以通过应用第一个函数来实现,然后回到f,最后应用第二个函数。我们需要解决这个问题,看看我的假设是否合适,这种方法是否有效,以及它是否会导致对您的目的有用的东西。

【讨论】:

  • "哪个类别将具有f a -&gt; m b 类型的函数作为箭头" — 我不知道箭头,但这些对象不是在Hask 上的两个内函子的逗号类别中吗:@ 987654344@ 和 m?不过,不知道它给了我们什么。 compAbsorb 对我来说非常不满意:一方面,我不希望 f b -&gt; m c 成为单子态射,因为我的 f 有一个相当虚拟的单子实例,对于两个,我的用例(请参阅问题下的评论) 不需要从mf,我不想强​​加它。感谢您的回答,它向我澄清了一些事情。
  • @user3237465 查看您的代码似乎证实了您的期望。特别是,尝试通过尝试idAbsorb = sliftcompAbsorb = g . runDriveT . f 来做“显而易见”的事情是第一个障碍——compAbsorb idAbsorb f 不是f(它会将Stop 更改为More),所以我们甚至没有类别。从DriveT mm 会引起麻烦,而且,正如您所说,在您的用例的组合过程中这样做几乎没有意义。顺便说一句,请注意您的(&gt;~&gt;) 既不是(&gt;=&gt;) 也不是flip compAbsorb,这似乎证实了您确实想要别的东西。
猜你喜欢
  • 2011-04-27
  • 2012-10-24
  • 2013-08-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多