LiftM可以与liftA不同吗?

时间:2009-10-28 02:34:45

标签: haskell theory typeclass category-theory

根据the 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

(我从explanation at Wikipedia重新输入了这些默认定义,错误是我自己的,但如果有错误,至少原则上是可能的。)

由于目前已定义了库,我们有:

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(与<*>不同),只是{{1}的历史现实的结果1}}的设计并未考虑MonadPointed?或者他们是否采用其他行为方式(可能是某些合法的Applicative定义)与仅需要Monad上下文的版本不同?

如果它们不同,您是否可以提供一组简单的定义(遵守ApplicativeMonadApplicativePointed定义所需的法律。 Typeclassopedia和其他地方,但不是类型系统强制执行的)FunctorliftA表现不同?

或者,如果它们不相同,你能否使用与前提相同的法则来证明它们的等同性?

2 个答案:

答案 0 :(得分:22)

liftAliftMfmap. 应该都是相同的功能,他们必须如果他们满足仿函数法则:

fmap id = id

但是,Haskell不会对此进行检查。

现在申请。对于某些仿函数,ap<*>可能是不同的,因为可能存在多个满足类型和规律的实现。例如,List有多个可能的Applicative实例。您可以按如下方式声明申请表:

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

ap函数仍将定义为liftM2 id,这是Applicative个实例,每Monad个免费提供。但是这里有一个具有多个Applicative实例的类型构造函数的示例,这两个实例都满足法则。但是如果你的monad和你的应用函子不同意,那么为它们设置不同的类型被认为是好的形式。例如,上面的Applicative实例与[]的monad不一致,因此您应该说newtype ZipList a = ZipList [a]然后为ZipList而不是{{[]创建新实例1}}。

答案 1 :(得分:8)

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

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

你说得对:功能因历史原因而存在。人们对事情的发展方式有着强烈的想法。