IO 是 Functor 的一个实例仅仅是因为它首先是一个 Monad 吗?
Is IO an instance of Functor just because it is a Monad in the first place?
来自LYAH I understand that the do
notation is just syntactic sugar for monadic style; and from the wikibook 我读得差不多;所以我的理解是,如果没有 Monad
实例,就不会有任何 do
符号。
然而我读到了 IO
类型构造函数的 Functor
实例的定义。
instance Functor IO where
fmap f action = do
result <- action
return (f result)
这只是下面的语法糖,不是吗?
instance Functor IO where
fmap f action = action >>= return . f
这意味着基础假设 IO
首先是 Monad
的实例;这与每个 Monad
都是 Functor
而不是相反的事实相悖。
事实上,我已经理解 Monad
比 Applicative
更“重要”,而 Applicative
又比 Functor
更重要Applicative
的定义对其实例强制执行 Functor
约束(并且 Monad
的定义理想地要求其实例是 Applicative
,如 如果它不是 Applicative
).
,请不要将其设为 Monad
换句话说,上面的代码让我觉得如果 IO
不是 Monad
,就没有办法为 IO
编写 Functor
实例] 排在首位。
现在我想起来了,也许这就像说 IO
是作为成熟的 Monad
创建的,上面的实例后来只是为了完整性和数学一致性。
但是我很困惑,所以我在这里寻求帮助。
具有 Monad
实例的类型意味着它必须具有 Functor
(和 Applicative
)的定义,但这并不意味着 Functor
实例必须定义为“第一”,只是两个实例都必须存在。只要方法实现不是循环定义的,就没有问题。
事实上,通常先为一个类型实现Monad
,然后根据Monad
操作机械地定义Applicative
和Functor
,因为Monad
更强大,所以其他实例只是限制Monad
实例:
-- These work for any T with a Monad instance.
instance Functor T where
fmap f x = do
x' <- x
return (f x')
instance Applicative T where
pure = return
f <*> x = do
f' <- f
x' <- x
return (f' x')
这恰恰是因为“a Monad
‘不止于’ an Applicative
,而后者又‘不止于’ a Functor
".
还值得注意的是,最初 Monad
和 Functor
class 是不相关的, Applicative
class (后来添加的)是以及。每个函数都有单独的等效函数,例如 fmap
、liftA
和 liftM
; pure
和 return
; (<*>)
和 ap
; traverse
和 mapM
。按照惯例,您会编写一个 Monad
实例并据此实现其他 classes。这些单独的定义仍然存在,但现在是多余的:因为“Applicative–Monad Proposal”使 Applicative
成为 Monad
的超级 class 和 [=13= 的 Functor
],您可以始终使用例如pure
而不是 return
或 traverse
而不是 mapM
,因为它们是相同的函数,但在更严格的上下文中工作。因此,还有一些历史背景可以说明为什么一个类型的这些实例可能有单独的定义。
正如@dfeuer 指出的那样,有些数据结构 mapM
(mapM_
, forM
, forM_
) 比 traverse
更有效(分别为 traverse_
、for
、for_
),例如 Data.Vector
类型。在向量的特定情况下,我相信这是因为库可以利用单子排序作为优化,以实现更多的流式传输和就地分配结果。但它们是等价的,因为 traverse
应该总是产生相同的结果。
来自LYAH I understand that the do
notation is just syntactic sugar for monadic style; and from the wikibook 我读得差不多;所以我的理解是,如果没有 Monad
实例,就不会有任何 do
符号。
然而我读到了 IO
类型构造函数的 Functor
实例的定义。
instance Functor IO where
fmap f action = do
result <- action
return (f result)
这只是下面的语法糖,不是吗?
instance Functor IO where
fmap f action = action >>= return . f
这意味着基础假设 IO
首先是 Monad
的实例;这与每个 Monad
都是 Functor
而不是相反的事实相悖。
事实上,我已经理解 Monad
比 Applicative
更“重要”,而 Applicative
又比 Functor
更重要Applicative
的定义对其实例强制执行 Functor
约束(并且 Monad
的定义理想地要求其实例是 Applicative
,如 如果它不是 Applicative
).
Monad
换句话说,上面的代码让我觉得如果 IO
不是 Monad
,就没有办法为 IO
编写 Functor
实例] 排在首位。
现在我想起来了,也许这就像说 IO
是作为成熟的 Monad
创建的,上面的实例后来只是为了完整性和数学一致性。
但是我很困惑,所以我在这里寻求帮助。
具有 Monad
实例的类型意味着它必须具有 Functor
(和 Applicative
)的定义,但这并不意味着 Functor
实例必须定义为“第一”,只是两个实例都必须存在。只要方法实现不是循环定义的,就没有问题。
事实上,通常先为一个类型实现Monad
,然后根据Monad
操作机械地定义Applicative
和Functor
,因为Monad
更强大,所以其他实例只是限制Monad
实例:
-- These work for any T with a Monad instance.
instance Functor T where
fmap f x = do
x' <- x
return (f x')
instance Applicative T where
pure = return
f <*> x = do
f' <- f
x' <- x
return (f' x')
这恰恰是因为“a Monad
‘不止于’ an Applicative
,而后者又‘不止于’ a Functor
".
还值得注意的是,最初 Monad
和 Functor
class 是不相关的, Applicative
class (后来添加的)是以及。每个函数都有单独的等效函数,例如 fmap
、liftA
和 liftM
; pure
和 return
; (<*>)
和 ap
; traverse
和 mapM
。按照惯例,您会编写一个 Monad
实例并据此实现其他 classes。这些单独的定义仍然存在,但现在是多余的:因为“Applicative–Monad Proposal”使 Applicative
成为 Monad
的超级 class 和 [=13= 的 Functor
],您可以始终使用例如pure
而不是 return
或 traverse
而不是 mapM
,因为它们是相同的函数,但在更严格的上下文中工作。因此,还有一些历史背景可以说明为什么一个类型的这些实例可能有单独的定义。
正如@dfeuer 指出的那样,有些数据结构 mapM
(mapM_
, forM
, forM_
) 比 traverse
更有效(分别为 traverse_
、for
、for_
),例如 Data.Vector
类型。在向量的特定情况下,我相信这是因为库可以利用单子排序作为优化,以实现更多的流式传输和就地分配结果。但它们是等价的,因为 traverse
应该总是产生相同的结果。