首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Traversable如何使用这样一个事实:它同时继承了Foldable和Functor这两个子类?

Traversable如何使用这样一个事实:它同时继承了Foldable和Functor这两个子类?
EN

Stack Overflow用户
提问于 2019-07-30 12:01:37
回答 3查看 384关注 0票数 10
代码语言:javascript
复制
class (Functor t, Foldable t) => Traversable t where

    traverse :: Applicative f => (a -> f b) -> t a -> f (t b)
    traverse g = sequenceA . fmap g

    sequenceA :: Applicative f => t (f a) -> f (t a)
    sequenceA = traverse id

Traversable如何利用它同时继承了FoldableFunctor这一事实

作为一种可遍历类型,t意味着t也是一种函数式类型和一种可折叠类型。

我看到在traverse中使用了t是一个函数式类型,即fmap

t是一种可折叠类型的事实是否在某些地方被使用?

traverse是否利用了t是可折叠类型的事实?

sequenceA使用哪个事实:t是函数式类型,t是可折叠类型,还是两者兼而有之?

我们能定义一个只是Functor的子类的类,并且以相同的方式定义traversesequenceA函数吗?

谢谢。

EN

回答 3

Stack Overflow用户

发布于 2019-07-30 12:12:39

未使用Foldable实例。尽管如此,请求Foldable是很好的,因为如果我们可以traverse一个东西,那么我们就可以foldMap它:

代码语言:javascript
复制
foldMapDefault :: (Traversable t, Monoid m) => (a -> m) -> t a -> m
foldMapDefault f = fst . traverse (\a -> (f a, ()))

这里的基本思想是使用标准的编写器monad;由于编写器的绑定操作使用mappend来组合“写入”部分--这里是f a值-- traverse将把正确的东西绑定在一起( mappend )。(它还将构建一个我们实际上并不关心的t ();丢弃这一部分是fst的工作。)

为了简单和自包含,我使用了编写器monad,但真正的实现使用了稍微让人费解的Const应用程序,以避免构建(然后丢弃)毫无意义的t ()值。您可以查看foldMapDefault here及其实现here的文档。

票数 13
EN

Stack Overflow用户

发布于 2019-07-30 12:16:49

here中,类Traversable是一个Functor和一个Foldable,并且必须满足以下规则:

Foldable可以看到更多here。这意味着它可以折叠(foldMap,foldr,foldl...)

traverse函数必须满足以下规则:

  • naturality:

T.遍历f=遍历(t .f)对于每个应用变换t

  • 恒等式

遍历标识= Identity

  • composition

traverse (合成fmap g.f) =作曲。fmap (导线g)。遍历f

和sequenceA:

  • 自然性

T.sequenceA = sequenceA。

  • 恒等式的每个应用变换的fmap t

sequenceA。fmap标识= Identity

  • composition

sequenceA。fmap Compose = Compose。fmap sequenceA。sequenceA

sequenceA使用哪个事实:不是函数式类型,不是可折叠类型,还是两者兼而有之?

Traversable,正如它的定义所说(以及上面引用的法律):

代码语言:javascript
复制
class (Functor t, Foldable t) => Traversable t where

既是一个Functor,又是一个可折叠的,根据它必须遵守的定律,它不仅是一个函数式的,比函数式更具体(但仍然是函数式的,因为它满足函数式的规律,可以使用它的类型类接口的函数),甚至比Foldable更具体,因此功能强大,不那么通用,有更多的约束。

事实是什么呢?定义,但为什么Traversable的设计者选择这两个?因为这很有用,正如你在@Daniel Wagner的回答中看到的那样。其他示例:

代码语言:javascript
复制
instance Traversable [] where
    traverse f = List.foldr cons_f (pure [])
      where cons_f x ys = liftA2 (:) (f x) ys

这个使用的是foldr

代码语言:javascript
复制
instance Foldable [] where
    elem    = List.elem
    foldl   = List.foldl
    foldl'  = List.foldl'
    foldl1  = List.foldl1
    foldr   = List.foldr
    foldr1  = List.foldr1
    length  = List.length
    maximum = List.maximum
    minimum = List.minimum
    null    = List.null
    product = List.product
    sum     = List.sum
    toList  = id

因此,Traverse既是Functor又是Foldable,因此您可以在需要时使用其接口的函数。(如示例所示,这只是一个示例,而不是设计人员选择使用FunctorFoldable定义Traversable的理由),因为它很有用。

票数 4
EN

Stack Overflow用户

发布于 2019-07-30 20:22:45

一般来说,子类化有两个主要原因:

  1. 你需要这个类来让你的定义生效,或者至少它让实现变得更加清晰,省略它并没有什么实际意义。这就是Functor的情况。
  2. 你可以从你的主定义中已经有的部分免费派生出另一个类,所以你也可以声明它。这就是Foldable.

的情况

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57264117

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档