我觉得问这个问题很傻,但这个问题已经在我的脑海中徘徊了一段时间,我找不到任何答案。
所以问题是:为什么应用函数器可以有副作用,而函数器不能?
也许他们可以,但我从来没有注意到...?
发布于 2013-01-29 18:15:41
这个答案有点过于简单,但如果我们将副作用定义为受以前的计算影响的计算,很容易看出Functor类型类不足以处理副作用,因为没有办法链接多个计算。
class Functor f where
fmap :: (a -> b) -> f a -> f b函数器唯一能做的事情就是通过一些纯函数a -> b来改变计算的最终结果。
但是,应用函数器添加了两个新函数:pure和<*>。
class Functor f => Applicative f where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b<*>是这里的关键区别,因为它允许我们链接两个计算:f (a -> b) (产生函数的计算)和f a (提供函数所应用的参数的计算)。使用pure和<*>可以定义例如
(*>) :: f a -> f b -> f b它简单地链接了两次计算,丢弃了第一次计算的最终结果(但可能会应用“副作用”)。
因此,简而言之,它是链式计算的能力,这是对计算中可变状态等效果的最低要求。
发布于 2013-01-29 18:57:04
Functor没有效果的说法是不正确的。每个Applicative (以及通过WrappedMonad的每个Monad )都是一个Functor。主要的区别是Applicative和Monad提供了如何使用这些效果,如何组合它们的工具。粗略地
Applicative允许您对效果进行排序和组合值。此外,inside.Monad还允许您根据前一个效果的结果确定下一个效果。然而,Functor只允许你修改里面的值,它没有提供工具来做任何与效果相关的事情。因此,如果某些东西只是Functor而不是Applicative,并不意味着它没有效果。它只是没有一个机制如何以这种方式将它们组合在一起。
更新:以为例,请考虑
import Control.Applicative
newtype MyF r a = MyF (IO (r, a))
instance Functor (MyF r) where
fmap f (MyF x) = MyF $ fmap (fmap f) x这显然是一个带有效果的Functor实例。只是我们没有办法定义符合Applicative的具有这些效果的操作。除非我们对r施加一些额外的约束,否则无法定义Applicative实例。
发布于 2013-01-30 09:43:50
这里的其他答案正确地表明,函数器不允许副作用,因为它们不能组合或排序,这在很大程度上是正确的,但有一种方法可以对函数器进行排序:向内排序。
让我们编写一个有限的Writer函数器。
data Color = R | G | B
data ColorW a = Re a | Gr a | Bl a deriving (Functor)然后将Free monad类型应用于它
data Free f a = Pure a | Free (f (Free f a))
liftF :: Functor f => f a -> Free f a
liftF = Free . fmap Pure
type ColorWriter = Free ColorW
red, blue, green :: a -> ColorWriter a
red = liftF . Re
green = liftF . Gr
blue = liftF . Bl当然,通过自由属性,这形成了一个单体,但效果实际上来自函数器的“层”。
interpretColors :: ColorWriter a -> ([Color], a)
interpretColors (Pure a) = ([], a)
interpretColors (Free (Re next)) = let (colors, a) = interpretColors next
in (R : colors, a)
...所以,这是一种技巧。实际上,“计算”是由自由单体引入的,但计算的材料,隐藏的上下文,只是由一个函数器引入的。事实证明,您可以对任何数据类型执行此操作,它甚至不需要是Functor,但Functor提供了一种清晰的方法来构建它。
https://stackoverflow.com/questions/14576543
复制相似问题