Applicative IO 是基于 Monad IO 的函数实现的吗?
在“为大善而学 Haskell!”作者声称 Applicative IO
实例是这样实现的:
instance Applicative IO where
pure = return
a <*> b = do
f <- a
x <- b
return (f x)
我可能是错的,但似乎 return
和 do
特定的构造(一些糖化绑定 (>>=)
) 来自 Monad IO
。假设这是正确的,我的实际问题是:
为什么Applicative IO
实现依赖于Monad IO
函数/组合器?
不是Applicative< /code> 不如比
Monad
强大的概念?
编辑(一些说明):
这种实现违背了我的直觉,因为根据 Typeclassopedia 文章,给定类型需要在它之前Applicative
可以制成Monad
(或者理论上应该如此)。
In "Learn You a Haskell for Great Good!" author claims that Applicative IO
instance is implemented like this:
instance Applicative IO where
pure = return
a <*> b = do
f <- a
x <- b
return (f x)
I might be wrong, but it seems that both return
, and do
-specific constructs (some sugared binds (>>=)
) comes from Monad IO
. Assuming that's correct, my actual question is:
Why Applicative IO
implementation depends on Monad IO
functions/combinators?
Isn't Applicative
less powerfull concept than Monad
?
Edit (some clarifications):
This implementation is against my intuition, because according to Typeclassopedia article it's required for a given type to be Applicative
before it can be made Monad
(or it should be in theory).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
是的,除了你的括号之外,这正是这里的问题。理论上,任何
Monad
应该 也是一个Applicative
,但由于历史原因(即,因为Monad
已经存在了更长的时间)。这也不是 Monad 的唯一特性。考虑相关类型类的实际定义,取自 Hackage 上的
base
包的源代码。这是
Applicative
:...关于它,我们可以观察到以下内容:
Functor
。同时,这里是
Monad
:...关于它,我们可以观察到以下内容:
Applicative
,而且还忽略了Functor
,两者都忽略了。这些在逻辑上由 Monad 隐含,但没有明确要求。return
和join
的更数学自然的定义。fail
。一般来说,Monad 类型类与其所基于的数学概念的不同之处可以追溯到它作为编程抽象的历史。有些,比如它与 Applicative 共享的函数应用偏向,是函数式语言中存在的反映;其他的,例如
失败
或缺乏适当的类上下文,都是历史事故。归根结底,拥有一个
Monad
实例意味着一个Applicative
实例,而这又意味着一个Functor
实例>。类上下文只是明确地形式化了这一点;无论如何,这仍然是正确的。就目前情况而言,给定一个 Monad 实例,Functor 和 Applicative 都可以以完全通用的方式定义。Applicative
比Monad
更“强大”,但它更更通用:任何Monad
都是如果您复制并粘贴通用实例,但存在无法定义为Monad
的Applicative
实例,则会自动Applicative
。类上下文,例如 Functor f =>应用性 f 说明了两件事:后者意味着前者,并且必须存在一个定义来满足该含义。在许多情况下,定义后者无论如何都会隐式定义前者,但编译器通常无法推断出这一点,因此需要显式写出两个实例。使用
Eq
和Ord
可以观察到同样的事情 - 后者显然暗示了前者,但您仍然需要在中定义一个Eq
实例order 为Ord
定义一个。Yes, your parenthetical aside is exactly the issue here. In theory, any
Monad
should also be anApplicative
, but this is not actually required, for historical reasons (i.e., becauseMonad
has been around longer). This is not the only peculiarity ofMonad
, either.Consider the actual definitions of the relevant type classes, taken from the
base
package's source on Hackage.Here's
Applicative
:...about which we can observe the following:
Functor
.Meanwhile, here's
Monad
:...about which we can observe the following:
Applicative
, but alsoFunctor
, both of which are logically implied byMonad
but not explicitly required.return
andjoin
.fail
which doesn't really fit in at all.In general, the ways that the
Monad
type class differs from the mathematical concept it's based on can be traced back through its history as an abstraction for programming. Some, like the function application bias it shares withApplicative
, are a reflection of existing in a functional language; others, likefail
or the lack of an appropriate class context, are historical accidents more than anything else.What it all comes down to is that having an instance of
Monad
implies an instance forApplicative
, which in turn implies an instance forFunctor
. A class context merely formalizes this explicitly; it remains true regardless. As it stands, given aMonad
instance, bothFunctor
andApplicative
can be defined in a completely generic way.Applicative
is "less powerful" thanMonad
in exactly the same sense that it is more general: AnyMonad
is automaticallyApplicative
if you copy+paste the generalized instance, but there existApplicative
instances which cannot be defined as aMonad
.A class context, like
Functor f => Applicative f
says two things: That the latter implies the former, and that a definition must exist to fulfill that implication. In many cases, defining the latter implicitly defines the former anyway, but the compiler cannot deduce that in general, and thus requires both instances to be written out explicitly. The same thing can be observed withEq
andOrd
--the latter obviously implies the former, but you still need to define anEq
instance in order to define one forOrd
.IO
类型在 Haskell 中是抽象的,因此如果您想为IO
实现通用的Applicative
,您必须使用以下操作来实现:由IO支持。由于您可以根据Monad
操作来实现Applicative
,这似乎是一个不错的选择。你能想出另一种方法来实现它吗?是的,Applicative 在某种意义上不如 Monad 强大。
The
IO
type is abstract in Haskell, so if you want to implement a generalApplicative
forIO
you have to do it with the operations that are supported by IO. Since you can implementApplicative
in terms of theMonad
operations that seems like a good choice. Can you think of another way to implement it?And yes,
Applicative
is in some sense less powerful thanMonad
.是的,因此每当您有一个
Monad
时,您始终可以将其设为Applicative
。您可以将IO
替换为示例中的任何其他 monad,它将是一个有效的Applicative
实例。打个比方,虽然彩色打印机可能被认为比灰度打印机更强大,但您仍然可以使用彩色打印机来打印灰度图像。
当然,也可以将
Monad
实例基于Applicative
并设置return = pure
,但您将无法定义 <一般情况下,代码>>>=。这就是 Monad 变得更强大的意义。Yes, and therefore whenever you have a
Monad
you can always make it anApplicative
. You could replaceIO
with any other monad in your example and it would be a validApplicative
instance.As an analogy, while a color printer may be considered more powerful than a grayscale printer, you can still use one to print a grayscale image.
Of course, one could also base a
Monad
instance on anApplicative
and setreturn = pure
, but you won't be able to define>>=
generally. This is whatMonad
being more powerful means.在完美世界中,每个
Monad
都是一个Applicative< /code> (所以我们有
class Applicative a => Monad a where ...
),但由于历史原因,两个类型类都是独立的。因此,您认为这个定义有点“倒退”(使用更强大的抽象来实现不太强大的抽象)的观察是正确的。In a perfect world every
Monad
would be anApplicative
(so we hadclass Applicative a => Monad a where ...
), but for historical reasons both type classes are independend. So your observation that this definition is kind of "backwards" (using the more powerful abstaction to implement the less powerful one) is correct.对于旧版本的 GHC,您已经有了完美的答案,但在最新版本中,您实际上确实有
class Applicative m =>; Monad m
所以你的问题需要另一个答案。就 GHC 实现而言:GHC 只是在尝试编译任何实例之前检查为给定类型定义了哪些实例。
从代码语义上来说:
class Applicative m => Monad m
并不意味着必须“首先”定义 Applicative 实例,只是如果在程序结束时尚未定义它,那么编译器将中止。You already have perfectly good answers for older versions of GHC, but in the latest version you actually do have
class Applicative m => Monad m
so your question needs another answer.In terms of GHC implementation: GHC just checks what instances are defined for a given type before it tries to compile any of them.
In terms of code semantics:
class Applicative m => Monad m
doesn't mean theApplicative
instance has to be defined "first", just that if it hasn't been defined by the end of your program then the compiler will abort.