Что в объективе я должен использовать для создания геттера только для чтения по индексу?

У меня есть тип, внутренние детали которого скрыты. Я хочу предоставить какую-то линзу, которая может считывать элементы указанного типа по определенным индексам, но не изменять их. Экземпляр Ixed для моего типа, похоже, не делает то, что я хочу, поскольку он явно разрешает модификации (но не вставки или удаления). Я не уверен, что я использую, если я хочу разрешить индексирование только для чтения.


person Koz Ross    schedule 03.09.2016    source источник
comment
Вы можете использовать Traversal' возвращено ix< /a>, но просто присвойте ему тип Fold. Складки в некотором смысле являются обходами только для чтения. Конечно, это не поможет вам, если тип абстрактный и вы не можете писать в него, потому что вы не сможете создать экземпляр Ixed.   -  person Benjamin Hodgson♦    schedule 04.09.2016


Ответы (1)


Если вы хотите определить объектив только для чтения, используйте тип Getter. Сначала рассмотрим простой пример. Вы можете получить доступ к элементу по индексу, используя функции ^? и ix.

λ: [1..] ^? ix 10
Just 11
λ: import qualified Data.Map as M
λ: M.empty ^? ix 'a'
Nothing
λ: M.singleton 'a' 3 ^? ix 'a'
Just 3

Так что это был пример того, как вы можете использовать стандартные линзы для доступа к индексированным структурам данных. Этих знаний должно быть достаточно, чтобы определить свой собственный индексированный геттер только для чтения, но я приведу расширенный пример.

{-# LANGUAGE RankNTypes      #-}
{-# LANGUAGE TemplateHaskell #-}

import Control.Lens

data MyData = MkData
    { _innerList  :: [Int]
    , _dummyField :: Double
    }

makeLenses ''MyData

indexedGetter :: Int -> Getter MyData (Maybe Int)
indexedGetter i = innerList . to (^? ix i)

Теперь в ghci вы можете использовать этот геттер.

λ: let exampleData = MkData [2, 1, 3] 0.3 
λ: exampleData ^. indexedGetter 0
Just 2
λ: exampleData & indexedGetter 0 .~ Just 100

<interactive>:7:15:
    No instance for (Contravariant Identity)
      arising from a use of ‘indexedGetter’
    In the first argument of ‘(.~)’, namely ‘indexedGetter 0’
    In the second argument of ‘(&)’, namely
      ‘indexedGetter 0 .~ Just 100’
    In the expression: exampleData & indexedGetter 0 .~ Just 100
person Shersh    schedule 04.09.2016