【问题标题】:Understanding signature of function traverse in haskell了解haskell中函数遍历的签名
【发布时间】:2016-04-01 08:14:54
【问题描述】:
traverse :: Applicative f => (a -> f b) -> t a -> f (t b)

嗨,
有很多我无法理解签名的功能。当然我知道 traverse 有两个参数,第一个是函数。然而,
(a -> f b) 是什么意思?我能理解(a -> b).
同理,t af (t b)

你能解释一下吗?

【问题讨论】:

  • f 代表类型构造函数(想想f = Maybe),t 也是如此(想想t = [])——你能理解(a -> Maybe b) -> [a] -> Maybe [b]吗?
  • 如果你想感受一下这个案例,你可以用traverse (\ a -> if even a then Just (a `div` 2) else Nothing) [2,4,6]玩一下(尝试改变输入列表);)
  • 谢谢。请告诉我:t a 总是意味着 [a] ?
  • 另外,为什么我们使用 traverse 而不是 map ?
  • 对第一个问题:不! t a = [a] 只是一个示例(这就是为什么您首先希望拥有 parametric t 的原因)

标签: haskell type-signature


【解决方案1】:

traverse 是一个类型分类函数,所以遗憾的是,这个函数的行为取决于我们选择 t 的确切含义。这与>>=fmap 不同。然而,它的行为是有规则的,就像在那些情况下一样。这些规则应该捕捉到traverse 采用函数a -> f b 的想法,这是从ab 的有效转换,并将其提升到在as 的整个“容器”上工作,收集每个局部变换的效果。

例如,如果我们有Maybe atraverse 的实现将是

 traverse f (Just a) = Just <$> f a
 traverse f Nothing = pure Nothing

对于列表

 traverse f [a1, a2, ...] = (:) <$> f a1 <*> ((:) <$> f a2 <*> ...))

请注意我们如何利用“效果”f 不仅是函子,而且是可应用的这一事实,因此我们可以进行两个 f-ful 计算,f af b 并将它们粉碎在一起获取f (a, b)。现在我们想提出一些法则来解释所有 traverse 可以做的是将f 应用于元素并在收集外部效果的同时构建原始的t a 备份。我们这么说

 traverse Identity = Identity -- We don't lose elements
 t . traverse f = traverse (t . f) -- For nicely composing t
 traverse (Compose . fmap g . f) = Compose . fmap (traverse g) . traverse f

现在这看起来很复杂,但它所做的只是澄清“基本上四处走动并应用局部变换”的含义。所有这一切归结为,虽然您不能只阅读签名来理解 traverse 的作用,但对签名的直觉是正确的

  • 我们得到一个本地的、有效的函数f :: a -&gt; f b
  • 一个充满as的函子
  • 我们通过重复应用f 得到一个充满b 的函子,阿拉fmap
  • f 的所有效果都会累加,所以我们得到的是f (t b),而不仅仅是t b

但请记住,traverse 可能会以一些奇怪的方式被使用。例如,镜头包中塞满了使用traverse 和非常奇怪的函子来产生很好的效果。

作为一个快速测试,你能弄清楚如何使用合法的traverse 来实现fmap for t?那是

fmapOverkill :: Traversable f => (a -> b) -> (f a -> f b)

headMay

headMay :: Traversable t => t a -> Maybe a

这两者都是可遍历实例也满足FunctorFoldable这一事实的结果!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-11-19
    • 2014-04-15
    • 1970-01-01
    • 2018-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多