LiftM可以与liftA不同吗?

Dou*_*ean 30 theory haskell typeclass category-theory

根据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
Run Code Online (Sandbox Code Playgroud)

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

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

liftA :: (Applicative f) => (a -> b) -> f a -> f b
liftM ::       (Monad m) => (a -> b) -> m a -> m b
Run Code Online (Sandbox Code Playgroud)

和:

(<*>) :: (Applicative f) => f (a -> b) -> f a -> f b
ap    ::       (Monad m) => m (a -> b) -> m a -> m b
Run Code Online (Sandbox Code Playgroud)

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

我的问题是:liftM(来自截然不同liftA)和ap(从不同的<*>),仅仅是历史现实的结果Monad是没有设计PointedApplicative想法?或者它们是否与某些其他行为方式(可能是某些法律Monad定义)不同于仅需要Applicative上下文的版本?

如果它们是不同的,你可以提供一组简单的定义(服从所需要的法律Monad,Applicative,Pointed,和Functor在Typeclassopedia描述定义和其他地方而不是由类型系统执行)针对liftAliftM不同的表现?

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

Apo*_*isp 24

liftA,liftM,fmap,和. 应该都是相同的功能,而且必须是,如果他们满足函子法:

fmap id = id
Run Code Online (Sandbox Code Playgroud)

但是,Haskell不会检查这一点.

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

instance Applicative [] where
  (f:fs) <*> (x:xs) = f x : fs <*> xs
  _      <*> _      = []
  pure              = repeat
Run Code Online (Sandbox Code Playgroud)

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

  • 好的,这是真的,对于某些类型,有多个Applicative实例和多个Monad实例.但是,根据上面的定义,必须在Applicative实例和Monad实例之间共享pure/return实现.这是否意味着,为了满足法律,<*>和ap必须相同?看起来你的例子依赖于使用pure = repeat为[]创建一个Applicative实例,但仍然使用[]的Prelude Monad实例和return =([])? (2认同)
  • @Apocalisp:仅考虑 fmap 的类型,您仍然可以拥有异国情调的成员。附带条件 fmap id = id 足以解决这个问题,我认为您在 'f' 上添加的额外量词是作弊。;) Doug,虽然 Functor 的定义是独一无二的,但适用法律足够宽松以允许多个兼容的定义。然而,按照惯例,给定类型的 Monad 和 Applicative 应该兼容。 (2认同)

Mar*_*ijn 8

他们可以有所不同,但他们不应该.

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

你说得对:功能因历史原因而存在.人们对事情应该如何有强烈的想法.