我可以为具有常量索引的列表创建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
,但我仍然想知道为什么上面提到的方法不起作用..
答案 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
。