我正在研究Typeclassopedia中的Functors部分。
一个简单的直觉是,Functor代表某种“容器”,以及将函数统一应用于容器中每个元素的能力。
行。因此,对于像列表或树这样的归纳类型,仿函数看起来非常自然。
如果元素数量固定为较小的数字,那么Functors也会显得非常简单。例如,对于Maybe,您只需要关注" Nothing"或者"只是一个" - 两件事。那么,你如何制作类似图形的东西,可能有循环,一个Functor的实例?我认为更普遍的方式是,非归纳类型如何适应"仿函数?
我越是想到它,我就越意识到归纳/非归纳并不重要。归纳类型更容易为...定义fmap
如果我想将图形作为Functor的一个实例,我将不得不在fmap中实现图形遍历算法;例如,它可能必须使用一个辅助函数来跟踪被访问的节点。在这一点上,我现在想知道为什么还要把它定义为Functor而不仅仅是把它作为一个函数本身?例如。列表映射vs fmap ...?
我希望有经验,有战争故事和伤疤的人可以解释一下。谢谢!
答案 0 :(得分:8)
我们假设您定义了一个这样的图表
data Graph a = Node a [Graph a]
然后fmap
正好按照您的预期定义
instance Functor Graph where
fmap f (Node a ns) = Node (f a) (map (fmap f) ns)
现在,如果有一个循环,那么我们不得不做类似的事情
foo = Node 1 [bar]
bar = Node 2 [foo]
现在fmap
非常懒惰,您可以在不强制执行其余计算的情况下评估其部分结果,因此它与任何结关联的图形表示一样好!
一般来说这就是诀窍:fmap
是懒惰的,所以你可以像处理Haskell中的任何非归纳值一样对待它的结果(小心)。
此外,您应该定义fmap
vs。随后的其他函数
fmap
是一个很好的,众所周知的API,带有规则Functor
s Functor
,而不是您的图形一般来说,当我看到某些东西是一个仿函数时,我想"太棒了,我知道如何使用它"当我看到
superAwesomeTraversal :: (a -> b) -> Foo a -> Foo b
我有点担心这会做出意想不到的事情。