Traversable typeclass的用途 [英] The purpose of the Traversable typeclass

查看:102
本文介绍了Traversable typeclass的用途的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有人可以向我解释,类型类型 Traversable 的用途是什么?



类型类定义是:

  class(Functor t,Foldable t)=> Traversable(t :: *  - > *)其中

所以 / code>是 Functor t 可折叠t
$ b $ 遍历函数是 Traversable 的成员,并且有以下签名:


  traverse :: Applicative f => (a  - > f b) - > t a  - > f(t b)

为什么结果必须包含到应用程序中?它有什么意义?



我有以下示例:

  module ExercisesTraversable where 

import Test.QuickCheck(任意,任意)
import Test.QuickCheck.Checkers(quickBatch,eq,(= - =),EqProp)
import Test.QuickCheck.Classes(遍历)

类型TI = []

新类型IdentityT a = IdentityT a
派生(Eq,Ord,Show)

实例Functor IdentityT其中
fmap f(IdentityT a)= IdentityT(fa)

实例可折叠IdentityT其中
foldMap f(IdentityT a)= fa

instance可穿透的IdentityT,其中
遍历f(IdentityT a)= IdentityT< $> f a

实例任意a =>任意(IdentityT a)其中
任意=做
a< - 任意
返回(IdentityT a)

实例Eq a => EqProp(IdentityT a)其中(= - =)= eq

main = do
let trigger = undefined :: TI(Int,Int,[Int])
quickBatch可以遍历的触发器)

让我们来看看遍历执行:

 遍历f(IdentityT a)= IdentityT< $> fa 

应用程序的结果类型 fa 必须是一个应用程序,为什么?请问一个仿函数不够吗?

解决方案

身份一个不好的例子,因为它总是只包含一个值。你是对的 - 在这种情况下, Functor f 约束就足够了。但很显然,大部分遍历的结构并不是那么简单。



遍历的作用是:它访问按照某种明确规定的顺序,容器中的所有元素对它们执行一些操作,并按原样重构结构。这比任何一个




  • Functor t 都更强大,它还允许您访问/修改所有元素并重构结构,但只能完全独立于彼此(从而允许选择任意的计算顺序,在任何元素已被(懒惰地)映射到所有元素之前,将结果返回给结构,等等)。

  • 可折叠t ,它使元素以线性顺序排列,但不重构结构。基本上, Foldable 就是可以降级到一个简单列表的容器类,如

      toList :: Foldable t => t a  - > [a] 

    ...或通过

    $连接任何monoidal类型b
    $ b

      foldMap ::(可折叠t,Monoid m)=> (a  - > m) - > t a  - > m 

    这里,每个元素的操作结果都是通过组合的(或者,如果没有元素,结果是 mempty )。




遍历的情况下, Applicative f 约束基本上解除了这个monoid组合到你可以重建结构的东西。这些信件是:

  mempty :: m 
pure mempty :: fm



 (<>) :: m  - > m  - > m 
liftA2(<>):: f m - > f m - > fm

...但是另外,因为 f 也是一个函数,你可以将本地结果包装在任何数据构造函数中,因此不仅构建一个通用列表类的东西,而且构建一个任意的容器,包括一个具有原始结构的容器。


Could someone please explain to me, what is the purpose of the typeclass Traversable?

The typeclass definition is:

class (Functor t, Foldable t) => Traversable (t :: * -> *) where

So Traversable is a Functor t and Foldable t.

The traverse function is a member of Traversable and has the following signature:

traverse :: Applicative f => (a -> f b) -> t a -> f (t b)

Why does the result have to be wrapped into an applicative? What is the sense of it?

I have the following example:

module ExercisesTraversable where

  import Test.QuickCheck (Arbitrary, arbitrary)
  import Test.QuickCheck.Checkers (quickBatch, eq, (=-=), EqProp)
  import Test.QuickCheck.Classes (traversable)

  type TI = []

  newtype IdentityT a = IdentityT a
    deriving (Eq, Ord, Show)

  instance Functor IdentityT where
    fmap f (IdentityT a) = IdentityT (f a)

  instance Foldable IdentityT where
    foldMap f (IdentityT a) = f a

  instance Traversable IdentityT where
    traverse f (IdentityT a) = IdentityT <$> f a

  instance Arbitrary a => Arbitrary (IdentityT a) where
    arbitrary = do
      a <- arbitrary
      return (IdentityT a)

  instance Eq a => EqProp (IdentityT a) where (=-=) = eq

  main = do
    let trigger = undefined :: TI (Int, Int, [Int])
    quickBatch (traversable trigger)  

Let's take a look at the traverse implementation:

traverse f (IdentityT a) = IdentityT <$> f a

The result type of the application f a has to be an applicative, why? Would a functor not be enough?

解决方案

Identity is a bit of a poor example as it always contains exactly one value. You're right – in this case, a Functor f constraint would be sufficient. But clearly, most traversables aren't so structurally trivial.

What traverse does is: it "visits", in some well-specified order, all elements in a container, performs some operation on them, and reconstructs the structure as it was. This is more powerful than either

  • Functor t, which also allows you to visit/modify all elements and reconstructs the structure, but only completely independent of one another (thus allowing to choose an arbitrary order-of-computation, returning a thunk to the structure before any of the elements have been (lazily) mapped at all, etc.).
  • Foldable t, which brings the elements in a linear order, but does not reconstruct the structure. Basically, Foldable is just the class of containers that can be demoted to a simple list, as witnessed by

    toList :: Foldable t => t a -> [a]
    

    ...or to a concatenation of any monoidal type, via

    foldMap :: (Foldable t, Monoid m) => (a -> m) -> t a -> m
    

    Here, the results of the operation on each element are combined through the monoid operation (or, in case the are no elements, the result is mempty).

In case of traverse, the Applicative f constraint basically lifts this monoid-combining to something in which you can also reconstruct the structure. The correspondence is

mempty      ::   m
pure mempty :: f m

and

(<>)        ::   m ->   m ->   m
liftA2 (<>) :: f m -> f m -> f m

...but in addition, because f is also a functor, you can wrap the local results in any data constructor and thus build not only a generic list-like thing but an arbitrary container, including one with the original structure.

这篇关于Traversable typeclass的用途的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆