关于编写索引镜头的困惑

时间:2017-08-24 11:44:45

标签: haskell 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,但我仍然想知道为什么上面提到的方法不起作用..

1 个答案:

答案 0 :(得分:2)

(<.)期望左侧有一个索引的光学元件,但是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