What should I use in the lens to create read-only by index?

I have a type whose internal data is hidden. I want to provide a lens that can read elements from a specified type at specific indices, but not change them. The instance Ixedfor my type does not seem to do what I want, since it explicitly allows modifications (although not insertion or deletion). I'm not sure what I use if I want to allow read-only indexing.

+4
source share
1 answer

If you want to define a read-only lens, you must use a type Getter. Let's look at a simple example first. You can access an item by index using the ^?and functions 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

So, this was an example of how you can use standard lenses to access indexed data structures. This knowledge should be enough to define your own indexed read-only, but I will give an extended example.

{-# 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)

Now in ghci you can use this getter.

λ: 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
+2
source

Source: https://habr.com/ru/post/1653553/


All Articles