2016-11-21 110 views
6

下面是我们如何定义KleisliFunctor与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 

+0

您是否有一些特殊的示例类型允许使用'Absorb'实例,但没有足够强大的标准实例来实现'(>>〜)'和'ajoin'? – leftaroundabout

+0

@leftaroundabout,我需要'Absorb'来实现一般化的monadic折叠,它允许在'f'函数中保留一个累加器,但将结果返回到'm'单子。见例如[本](https://github.com/effectfully/prefolds/blob/374257b12f9a2af752862addafe456cded9c0efb/test/Main.hs#L297)。 – user3237465

回答

4

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

我们先考虑KleisliFunctor,注重绑定样箭头映射:

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

对于这实际上是从m的Kleisli类别函子来Haskkmap一直遵守相关的函子法则:

-- 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 

事实上,有两个Functor s涉及使事情有点不寻常,b这并非不合理 - 例如,法律确实适用于mapMaybe,这是KleisliFunctor后暗示的第一个具体示例。

至于Absorb,我会翻转绑定样方法清楚起见:

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

如果我们要寻找到KleisliFunctor东西类似,立即出现一个问题是哪些类别将有功能类型为f a -> m b,如箭头所示。它肯定不能是哈斯克,因为它的身份(类型f a -> 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并最终应用第二个函数来实现。我们需要解决这个问题,以便了解我的假设是否合适,如果这种方法有效,以及它是否会为您的目的提供有用的信息。

+0

“哪个类别的函数的类型为'fa - > mb'为箭头” - 我不知道箭头,但是这些对象不在'Hask'上的两个endofunctor的逗号类中:'f'和' M'?不知道它给了我们什么。'compAbsorb'对我来说非常不满意,因为我不希望'fb - > mc'成为单态射线,因为我的'f'有一个相当虚拟的monad实例,我的用例是两个,在这个问题下)并不需要从'm'到'f',我不想强​​加这一点。感谢你的回答,它已经澄清了一些事情给我。 – user3237465

+1

@ user3237465看着你的代码似乎证实了你的期望。特别是试图通过尝试'idAbsorb = slift'和'compAbsorb = g来做“明显的”事情。 runDriveT。 f'落在第一个障碍 - compAbsorb idAbsorb f'不是'f'(它将'Stop'变成'More'),所以我们甚至没有一个类别。从'DriveT m'到'm'会产生麻烦,正如你所说的,在你的用例的组合过程中做这件事很没有意义。顺便说一句,请注意你的'(>〜>)'既不是'(> =>)'也不是'flip compAbsorb',这似乎证实你确实需要别的东西。 – duplode