2015-01-22 3 views
8

В библиотеке объективов Haskell, и element оба берут Int a, могут использоваться, например. для чтения или записи элемента списка в какой-то индекс, как этотВ чем разница между ix и элементом в библиотеке объективов Haskell

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?

ответ

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" 
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 ему присваивается тип ключа в качестве индекса, и пытается переключиться, что вокруг дает ошибку типа.

3

element работает, прогуливаясь по всей структуре, подсчитывая элементы и перемещая элемент с целевым индексом. Поэтому он всегда имеет временную сложность O (n) в размере структуры и работает только с индексами Int.

В отличие от этого ix имеет свой класс Ixed, а экземпляры полагаются на операции поиска/изменения конкретных структур данных. Например, ix для Data.Sequence является O (log n).

Однако ix работает только на определенных структур данных, в то время как elementOf работает с любым Traversal, Lens или Iso, например:

[0..10] ^? elementOf (reversed . each . filtered odd) 1 
-- Just 7 
+0

Спасибо. +1 для упоминания сложности, я действительно беспокоился об этом. Это имеет полный смысл. Так что, по возможности, мы должны использовать ix. – Stephan