在Haskell的镜头库中,ix
和element
都可以使用Int和在某个索引处读取或写入列表元素,如此
ghci> [1..10] ^? ix 4
Just 5
ghci> [1..10] & ix 4 .~ 1
[1,2,3,4,1,6,7,8,9,10]
同样地:
ghci> [1..10] ^? element 4
Just 5
ghci> [1..10] & element 4 .~ 1
[1,2,3,4,1,6,7,8,9,10]
element
和ix
之间的区别是什么?
答案 0 :(得分:11)
使用ix
,您不仅可以按号码进行索引,还可以使用例如地图中的关键。 element
订单中的Traverse
索引。
λ> let m = Map.fromList [("foo", 'f'), ("bar", 'b')]
λ> m ^? ix "foo"
Just 'f'
λ> m ^? element 0 -- Map is ordered container!
Just 'b'
差异更明显,例如IntMap
λ> let im = IntMap.fromList [(1, "one"), (2, "two")]
λ> im ^? ix 1
Just "one"
λ> im ^? element 1
Just "two"
答案 1 :(得分:4)
element
被定义为与Traversable
类的类型一起使用,甚至是镜头库不知道的类成员。因此,它仅使用Traversable
函数来访问该值,该值没有任何特定于值类型的索引类型的概念。因此,仅支持Int
索引,以通常的遍历顺序给出元素。
element
也提供了IndexedTraversal
,提供了一些处理索引的额外方法。
ix
仅针对镜头库所知的类型定义,但作为回报,它可以使用取决于值类型的不同索引类型。
对于列表,它们给出相同的结果。但可以看出差异,例如Data.Map
:
Prelude Control.Lens Data.Map> singleton "a" 3 ^? element "a"
<interactive>:19:28:
Couldn't match expected type ‘Int’ with actual type ‘[Char]’
In the first argument of ‘element’, namely ‘"a"’
In the second argument of ‘(^?)’, namely ‘element "a"’
In the expression: singleton "a" 3 ^? element "a"
Prelude Control.Lens Data.Map> singleton "a" 3 ^? ix "a"
Just 3
Prelude Control.Lens Data.Map> singleton "a" 3 ^? element 0
Just 3
Prelude Control.Lens Data.Map> singleton "a" 3 ^? ix 0
<interactive>:22:23:
Could not deduce (Num [Char]) arising from the literal ‘0’
from the context (Num a)
bound by the inferred type of it :: Num a => Maybe a
at <interactive>:22:1-23
In the first argument of ‘ix’, namely ‘0’
In the second argument of ‘(^?)’, namely ‘ix 0’
In the expression: singleton "a" 3 ^? ix 0
正如您所看到的,使用element
时,地图会被赋予Int
个索引,而使用ix
时,会将密钥类型指定为索引,并尝试将其切换为类型错误。
答案 2 :(得分:3)
element
通过遍历整个结构,计算元素并使用目标索引遍历元素来工作。因此,它总是具有结构大小的时间复杂度O(n),并且它仅适用于Int
索引。
相反,ix
有自己的类Ixed
,实例依赖于特定数据结构的查找/修改操作。例如,ix
的{{1}}为O(log n)。
但是,Data.Sequence
仅适用于特定数据结构,而ix
适用于任何elementOf
,Traversal
或Lens
,例如:
Iso