element
is defined to work with types of the Traversable
class, even class members which the lens library doesn't know about. As such it uses only Traversable
functions to access the value, which have no concept of any index type specific to the type of value. As such, only Int
indices are supported, giving elements in the usual traversal order.
element
also gives an IndexedTraversal
, giving some extra ways of handling indices.
ix
is only defined for types the lens library knows about, but in return it can use different index types dependent on the type of the value.
For lists they give the same result. But the difference can be seen e.g. for 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
As you can see, with element
the map is given Int
indices, while with ix
it is given the key type as index, and trying to switch that around gives a type error.