简体   繁体   English

使 Applicative 成为 Monad 所需的“最低限度”是多少?

[英]What is the 'minimum' needed to make an Applicative a Monad?

The Monad typeclass can be defined in terms of return and (>>=) . Monad类型类可以根据return(>>=) However, if we already have a Functor instance for some type constructor f , then this definition is sort of 'more than we need' in that (>>=) and return could be used to implement fmap so we're not making use of the Functor instance we assumed.但是,如果我们已经有某个类型构造函数fFunctor实例,那么这个定义有点“超出我们的需要”,因为(>>=)并且return可用于实现fmap所以我们没有使用我们假设的Functor实例。

In contrast, defining return and join seems like a more 'minimal'/less redundant way to make f a Monad .相比之下,定义returnjoin似乎是使f成为Monad的更“最小”/更少冗余的方式。 This way, the Functor constraint is essential because fmap cannot be written in terms of these operations.这样, Functor约束是必不可少的,因为就这些操作而言, fmap无法编写。 (Note join is not necessarily the only minimal way to go from Functor to Monad : I think (>=>) works as well.) (注意join不一定是从FunctorMonad的唯一最小方法:我认为(>=>)也有效。)

Similarly, Applicative can be defined in terms of pure and (<*>) , but this definition again does not take advantage of the Functor constraint since these operations are enough to define fmap .类似地, Applicative可以用pure(<*>)定义,但是这个定义再次没有利用Functor约束,因为这些操作足以定义fmap

However, Applicative f can also be defined using unit :: f () and (>*<) :: fa -> fb -> f (a, b) .但是, Applicative f也可以使用unit :: f ()(>*<) :: fa -> fb -> f (a, b) These operations are not enough to define fmap so I would say in some sense this is a more minimal way to go from Functor to Applicative .这些操作不足以定义fmap所以我会说从某种意义上说这是从FunctorApplicative一种更简单的方法。

Is there a characterization of Monad as fmap , unit , (>*<) , and some other operator which is minimal in that none of these functions can be derived from the others? Monad是否有一个特征为fmapunit(>*<)和其他一些最小的运算符,因为这些函数都不能从其他函数派生出来?

  • (>>=) does not work, since it can implement a >*< b = a >>= (\\ x -> b >>= \\ y -> pure (x, y)) where pure x = fmap (const x) unit . (>>=)不起作用,因为它可以实现a >*< b = a >>= (\\ x -> b >>= \\ y -> pure (x, y))其中pure x = fmap (const x) unit
  • Nor does join since m >>= k = join (fmap km) so (>*<) can be implemented as above.由于m >>= k = join (fmap km)所以(>*<)可以如上实现,也不会join
  • I suspect (>=>) fails similarly.我怀疑(>=>)同样失败。

I have something, I think.我有东西,我想。 It's far from elegant, but maybe it's enough to get you unstuck, at least.它远非优雅,但至少足以让你摆脱困境。 I started with join :: m (ma) -> ???我从join :: m (ma) -> ??? and asked "what could it produce that would require (<*>) to get back to ma ?", which I found a fruitful line of thought that probably has more spoils.并问“它会产生什么需要(<*>)才能回到ma ?”,我发现这是一个富有成效的思路,可能有更多的战利品。

If you introduce a new type T which can only be constructed inside the monad:如果你引入一个只能在 monad 内部构造的新类型T

t :: m T

Then you could define a join-like operation which requires such a T :然后你可以定义一个类似连接的操作,它需要这样一个T

joinT :: m (m a) -> m (T -> a)

The only way we can produce the T we need to get to the sweet, sweet a inside is by using t , and then we have to combine that with the result of joinT somehow.我们可以生产的唯一途径T ,我们需要得到的甜,甜a里面是用t ,然后我们要结合起来,与结果joinT莫名其妙。 There are two basic operations that can combine two m s into one: (<*>) and joinT -- fmap is no help.有两个基本操作可以将两个m合并为一个: (<*>)joinT -- fmap没有帮助。 joinT is not going to work, because we'll just need yet another T to use its result, so (<*>) is the only option, meaning that (<*>) can't be defined in terms of joinT . joinT不会工作,因为我们只需要另一个T来使用它的结果,所以(<*>)是唯一的选项,这意味着(<*>)不能根据joinT定义。

You could roll that all up into an existential, if you prefer.如果您愿意,您可以将所有内容汇总为存在主义。

joinT :: (forall t. m t -> (m (m a) -> m (t -> a)) -> r) -> r

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM