关于组成索引镜头的困惑

Confusion about composing indexed lens

我可以为具有常量索引的列表创建一个 IndexedTraversal,如下所示:

constIndexedList :: i -> Lens.AnIndexedTraversal i [a] [b] a b
constIndexedList _ _ [] = pure []
constIndexedList index f (x:xs) = (:) <$> Lens.indexed f index x <*> constListIndex index f xs

我宁愿通过组合两个更简单的镜头来创建它:

constIndex :: i -> Lens.AnIndexedLens i a b a b
constIndex index f = Lens.indexed f index

constIndexedList :: i -> Lens.AnIndexedTraversal i [a] [b] a b
constIndexedList index = Lens.cloneLens (constIndex index) <. traverse

然而,这无法进行类型检查,lens 中的类型错误不是我容易理解的类型错误:

• Couldn't match type ‘Lens.Indexed
                         i (t0 a) (Lens.Bazaar (Lens.Indexed i) a b (t0 b))’
                 with ‘[a] -> Lens.Bazaar (Lens.Indexed i) a b [b]’
  Expected type: Lens.Indexed
                   i (t0 a) (Lens.Bazaar (Lens.Indexed i) a b (t0 b))
                 -> [a] -> Lens.Bazaar (Lens.Indexed i) a b [b]
    Actual type: ([a] -> Lens.Bazaar (Lens.Indexed i) a b [b])
                 -> [a] -> Lens.Bazaar (Lens.Indexed i) a b [b]
• In the first argument of ‘(<.)’, namely
    ‘Lens.cloneLens (constIndex index)’
  In the expression: Lens.cloneLens (constIndex index) <. traverse

为什么我不能像这样合成索引镜头?

我最终找到了一种不同的模块化方法来做到这一点(Lens.reindexed (const index) Lens.traversed,但我仍然想知道为什么上面提到的方法不起作用..

(<.) 期望在其左侧有一个索引光学元件,但 cloneLens 给它一个未索引的镜头。

一个部分修复是使用 Lens.cloneIndexedLens 而不是 cloneLens

但是,A_/An_ 光学变量 (AnIndexedLens) 是参数类型,而不是结果类型,它可以使用常规光学变量 (IndexedLens ).这样一来,cloneIndexedLens 就变得不必要了。

constIndex :: i -> Lens.IndexedLens i a b a b
constIndex i f = Lens.indexed f i

constIndexedList :: i -> Lens.IndexedTraversal i [a] [b] a b
constIndexedList i = constIndex i <. traverse

单态输入和多态输出提高了可组合性。

IndexedLens 是多态类型(注意类型定义中的 forall 关键字)。

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

AnIndexedLens 是单态的。

type AnIndexedLens i s t a b = Optical (Indexed i) (->) (Pretext (Indexed i) a b) s t a b

每个 IndexedLens 都是 AnIndexedLens,但另一种方式的转换必须经过明确的 cloneIndexedLens