Как правильно заполнить некоторую сложную структуру данными из ввода-вывода, используя линзы? - PullRequest
1 голос
/ 02 ноября 2019
{- Some code to illustrate what I mean: -}
module Main where

import System.IO
import Control.Monad
import Control.Lens
import Data.UUID
import Data.UUID.V4

-- I have complex data structure (initially, JSON) and I can use
-- Data.Aeson.Lens to work with this structure. It's pretty comfortble
-- in most cases. But let's suppose we have broken data structure.
-- Instead of "a" I need to have unique key. Easiest way is to use GUID.
ds = [ [("a", "z"),("a", "x"),("a", "c")]
     , [("a", "v"),("a", "b"),("a", "n")]
     , [("a", "m"),("a", ","),("a", ".")]
     ]

-- So that's how we can get unique ID.
getId :: IO String
getId = toString <$> nextRandom

main :: IO ()
main = do
-- To insert unique ID I can use a awkward way like this:
-- generate pool of ids that is big enough.
    let count = length $ ds ^.. traversed <.> traversed
    ids <- forM [0..count * count] $ const getId
-- use Indexed Lens to have list of IDs for each data structure level
-- and insert ID from pre generated list where I need it
    let ds' = ds & traversed <.> traversed %@~
                 (\(i1, i2) v -> v & _1 %~
                    (\v' -> (ids !! (i1 * count + i2)) ++ v'))
    print ds'
-- It works. But I wonder if there is some better way to do the same.

1 Ответ

1 голос
/ 02 ноября 2019

Да, есть лучший способ. Вам просто не хватает некоторых предложений линз комбинаторов. Я предлагаю traverseOf, хотя он также имеет несколько других псевдонимов в библиотеке линз ... И все они просто реализованы как id в любом случае ...

ds' <- traverseOf (traverse . traverse . _1) (const getId) ds
...