32

根据Typeclassopedia(以及其他来源),Applicative逻辑上属于类型类层次结构中的MonadPointed(因此Functor)之间,所以如果今天编写 Haskell 前奏,我们理想情况下会有这样的东西:

class Functor f where
    fmap :: (a -> b) -> f a -> f b

class Functor f => Pointed f where
    pure :: a -> f a

class Pointed f => Applicative f where
    (<*>) :: f (a -> b) -> f a -> f b

class Applicative m => Monad m where
    -- either the traditional bind operation
    (>>=) :: (m a) -> (a -> m b) -> m b
    -- or the join operation, which together with fmap is enough
    join :: m (m a) -> m a
    -- or both with mutual default definitions
    f >>= x = join ((fmap f) x)
    join x = x >>= id
    -- with return replaced by the inherited pure
    -- ignoring fail for the purposes of discussion

(这些默认定义是我从维基百科的解释中重新输入的,错误是我自己的,但如果有错误,至少原则上是可能的。)

由于当前定义了库,因此我们有:

liftA :: (Applicative f) => (a -> b) -> f a -> f b
liftM ::       (Monad m) => (a -> b) -> m a -> m b

和:

(<*>) :: (Applicative f) => f (a -> b) -> f a -> f b
ap    ::       (Monad m) => m (a -> b) -> m a -> m b

请注意每对中这些类型之间的相似性。

我的问题是:(liftM与 不同liftA)和ap(与 不同<*>)仅仅是没有考虑和Monad设计的历史现实的结果吗?或者它们是否以某种其他行为方式(可能,对于某些法律定义)与只需要上下文的版本不同?PointedApplicativeMonadApplicative

如果它们是不同的,您能否提供一组简单的定义(遵守 Typeclassopedia 和其他地方描述的、但未由类型系统强制执行的定义的法律)Monad和行为不同?ApplicativePointedFunctorliftAliftM

或者,如果它们不是不同的,您能否使用与前提相同的定律证明它们的等价性?

4

2 回答 2

26

liftA, liftM, fmap, and . should all be the same function, and they must be if they satisfy the functor law:

fmap id = id

However, this is not checked by Haskell.

Now for Applicative. It's possible for ap and <*> to be distinct for some functors simply because there could be more than one implementation that satisfies the types and the laws. For example, List has more than one possible Applicative instance. You could declare an applicative as follows:

instance Applicative [] where
  (f:fs) <*> (x:xs) = f x : fs <*> xs
  _      <*> _      = []
  pure              = repeat

The ap function would still be defined as liftM2 id, which is the Applicative instance that comes for free with every Monad. But here you have an example of a type constructor having more than one Applicative instance, both of which satisfy the laws. But if your monads and your applicative functors disagree, it's considered good form to have different types for them. For example, the Applicative instance above does not agree with the monad for [], so you should really say newtype ZipList a = ZipList [a] and then make the new instance for ZipList instead of [].

于 2009-10-28T04:31:06.487 回答
9

他们可以不同,但​​他们不应该

它们可以不同,因为它们可以有不同的实现:一个在 an 中定义,instance Applicative另一个在 an 中定义instance Monad。但如果它们确实不同,那么我会说编写这些实例的程序员编写了误导性代码。

你是对的:这些功能的存在是出于历史原因。人们对事情应该如何发展有着强烈的想法。

于 2009-10-28T08:01:16.780 回答