为什么Haskell的镜头库里同时有itraverse和itraversed功能?

Why have both itraverse and itraversed functions in Haskell's lens library?

Haskell 库 lens contains a type class TraversableWithIndex that defines both the functions itraverse and itraversed:

class
    (FunctorWithIndex i t, FoldableWithIndex i t, Traversable t)
    => TraversableWithIndex i t | t -> i where
  itraverse :: Applicative f => (i -> a -> f b) -> t a -> f (t b)
  itraversed :: IndexedTraversal i (t a) (t b) a b

IndexedTraversal 展开如下:

type IndexedTraversal i s t a b =
  forall p f. (Indexable i p, Applicative f) => p a (f b) -> s -> f t

itraverseitraversed 看起来很相似。 为什么两者都需要?


itraverseitraversed 开始,似乎 itraversed 是两者中唯一可以与 %@~ as an AnIndexedSetter 一起使用的。

以下是 %@~AnIndexedSetterIndexed 的类型:

(%@~) :: AnIndexedSetter i s t a b -> (i -> a -> b) -> s -> t 

type AnIndexedSetter i s t a b =
  Indexed i a (Identity b) -> s -> Identity t 

newtype Indexed i a b = Indexed { runIndexed :: i -> a -> b }

为什么 %@~ 需要 AnIndexedSetter?为什么无论如何都必须使用 Indexed

使用 Indexed 似乎会使合成更加困难,因为它不是一个正常的函数。 我在这里错过了什么?

索引光学器件不像普通光学器件那么简单。正则Traversal很简单:

type Traversal s t a b = forall f. Applicative f => (a -> f b) -> s -> f t

这正是 traverses = c at = c b 的类型,其中 cTraversable

你可以想象 IndexedTraversal i(i -> a -> f b) 类似;但事实并非如此!

type IndexedTraversal i s t a b =
    forall p f. (Indexable i p, Applicative f) => p a (f b) -> s -> f t

Indexable i p约束被(->)Indexed满足,所以:

itraverse  :: Applicative f => (i -> a -> f b) -> s -> f t
itraversed :: Applicative f =>      (a -> f b) -> s -> f t  -- (->)
itraversed :: Applicativef  =>   Indexed i a b -> s -> f t

哪里

newtype Indexed i a b = Indexed { runIndexed :: i -> a -> b } 

为什么两者都需要? itraverse 更容易实现。通常 它已经存在(例如 containers 中的 traverseWithKey)。


操作需要具体的光学实例 (例如 set 需要 ASetter)。简而言之:编译器更容易理解 出东西,因为我们不使用 Rank2Types.

Indexed 即需要单独的 newtype 以便我们可以交谈 关于 a -> bi -> a -> b 作为 Indexable 的实例; 让我们将索引光学器件降级为常规光学器件:

Prelude Control.Lens> over itraversed (+1) [1,2,3]
[2,3,4]

并具有 p a (f b) -> q s (f t)(其中 p 可以是 (->)Indexable) 让我们组成索引和常规光学器件:

Prelude Control.Lens> over (itraversed . traversed)  (+1) [[1,2],[3]]
[[2,3],[4]]

Prelude Control.Lens> iover (itraversed . traversed) (,) [[1,2],[3]]
[[(0,1),(1,2)],[(0,3)]]