liftM 与 liftA 有什么不同吗?
根据Typeclassopedia(以及其他来源),Applicative
逻辑上属于类型类层次结构中的 Monad
和 Pointed
(以及 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
在设计时没有考虑到 Pointed
和 Applicative
?或者它们是否以某种其他行为方式(可能对于某些合法的 Monad 定义)与仅需要 Applicative 上下文的版本不同?
如果它们不同,您能否提供一组简单的定义(遵守 Monad
、Applicative
、Pointed
和 函子
定义在Typeclassopedia和其他地方描述,但不是由类型系统强制执行的),其中liftA
和liftM
的行为不同?
或者,如果它们不不同,您能否使用相同的定律作为前提来证明它们的等价性?
According to the Typeclassopedia (among other sources), Applicative
logically belongs between Monad
and Pointed
(and thus Functor
) in the type class hierarchy, so we would ideally have something like this if the Haskell prelude were written today:
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
(Where those default definitions were re-typed by me from the explanation at Wikipedia, errors being my own, but if there are errors it is at least in principle possible.)
As the libraries are currently defined, we have:
liftA :: (Applicative f) => (a -> b) -> f a -> f b
liftM :: (Monad m) => (a -> b) -> m a -> m b
and:
(<*>) :: (Applicative f) => f (a -> b) -> f a -> f b
ap :: (Monad m) => m (a -> b) -> m a -> m b
Note the similarity between these types within each pair.
My question is: are liftM
(as distinct from liftA
) and ap
(as distinct from <*>
), simply a result of the historical reality that Monad
wasn't designed with Pointed
and Applicative
in mind? Or are they in some other behavioral way (potentially, for some legal Monad
definitions) distinct from the versions that only require an Applicative
context?
If they are distinct, could you provide a simple set of definitions (obeying the laws required of Monad
, Applicative
, Pointed
, and Functor
definitions described in the Typeclassopedia and elsewhere but not enforced by the type system) for which liftA
and liftM
behave differently?
Alternatively, if they are not distinct, could you prove their equivalence using those same laws as premises?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
liftA
、liftM
、fmap
和.
应该都是相同的函数,如果它们满足函子定律,则它们必须:但是,Haskell 不会检查这一点。
现在来说说应用性的。对于某些函子来说,
ap
和<*>
可能是不同的,因为可能有多个实现满足类型和定律。例如,List 有多个可能的 Applicative 实例。您可以按如下方式声明应用程序:ap
函数仍将定义为liftM2 id
,这是免费提供的Applicative
实例每个Monad
。但这里有一个类型构造函数的示例,该构造函数具有多个 Applicative 实例,这两个实例都满足定律。但是,如果您的单子和应用函子不一致,那么为它们设置不同的类型被认为是一种很好的形式。例如,上面的Applicative
实例与[]
的 monad 不一致,因此您应该说newtype ZipList a = ZipList [a]
然后为ZipList
创建新实例,而不是[]
。liftA
,liftM
,fmap
, and.
should all be the same function, and they must be if they satisfy the functor law: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 possibleApplicative
instance. You could declare an applicative as follows:The
ap
function would still be defined asliftM2 id
, which is theApplicative
instance that comes for free with everyMonad
. But here you have an example of a type constructor having more than oneApplicative
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, theApplicative
instance above does not agree with the monad for[]
, so you should really saynewtype ZipList a = ZipList [a]
and then make the new instance forZipList
instead of[]
.它们可以不同,但不应该。
它们可能有所不同,因为它们可以有不同的实现:一个是在
实例 Applicative
中定义,而另一个是在实例 Monad
中定义。但如果它们确实不同,那么我会说编写这些实例的程序员编写了误导性代码。你是对的:这些功能的存在是出于历史原因。人们对于事情应该如何发展有着强烈的想法。
They can differ, but they shouldn't.
They can differ because they can have different implementations: one is defined in an
instance Applicative
while the other is defined in aninstance Monad
. But if they indeed differ, then I'd say the programmer who wrote those instances wrote misleading code.You are right: the functions exist as they do for historical reasons. People have strong ideas about how things should have been.