Как использовать iset с вложенным типом данных и линзами? - PullRequest
0 голосов
/ 09 марта 2020

Я не могу получить типы в последней функции для выравнивания. Смысл в том, чтобы установить удвоение всех цен в соединениях с функцией, которая зависит только от индекса 3-кортежа. Исходное значение Double в кортеже может быть отброшено.

{-# LANGUAGE TemplateHaskell   #-}
{-# LANGUAGE TupleSections #-}

import Control.Lens

data Typex = Typex 
    { _level       :: Int
    , _coordinate  :: (Int, Int)
    , _connections :: [(Int, (Int, Int), Double)]  -- = (level, coordinate, price)
    } deriving Show
makeLenses ''Typex

initTypexLevel :: Int -> Int -> Int -> [Typex] 
initTypexLevel a b c = [ Typex a (x, y) [(0,(0,0),0.0)]
                       | x <- [0..b], y <- [0..c]
                       ]

buildNestedTypexs :: [(Int, Int)] -> [[Typex]]
buildNestedTypexs pts
     = setConnectionsx [ initTypexLevel i y y
                      | (i,(_,y)) <- zip [0..] pts
                      ]

setConnectionsx :: [[Typex]] -> [[Typex]]
setConnectionsx (x:rest@(y:_)) = map (connect y) x : setConnectionsx rest
  where connect :: [Typex] -> Typex -> Typex
        connect txs tx
          = tx & connections .~ (map ((tx ^. level) + 1, , 0.0) $ txs ^.. traverse.coordinate)
setConnectionsx lst = lst

setInitPrices  :: [[Typex]] -> [[Typex]]
setInitPrices  (x:rest) = map setIndexPrices x : setInitPrices  rest
  where setIndexPrices :: Typex -> Typex
        setIndexPrices tx =  n & connections .~ ??? -- using iset (?), set the price in every 3-tuple so that price = f (index of the 3-tuple) where f = i*2
setInitPrices  lst = lst

1 Ответ

1 голос
/ 10 марта 2020

Вы, вероятно, ищете:

  where setIndexPrices :: Typex -> Typex
        setIndexPrices tx =  tx & connections .> traversed <. _3 .@~ f
        f i = 2 * fromIntegral i

Здесь .@~ - это версия оператора iset, а .> и <. - варианты используемого оператора композиции .. объединить индексированную оптику.

Если вы рассматриваете более простой неиндексированный opti c:

connections . traverse . _3

Этот opti c занимает TypeX, фокусируется на его _connections полях, Обходит список соединений и фокусируется на третьем поле (цена) каждого соединения. В результате получается opti c, который пересекает все цены в TypeX по порядку.

Чтобы проиндексировать этот opti c, нам нужно «обновить» неиндексированный traverse до индексированного traversed. Затем мы хотим использовать сохраняющие индекс операторы композиции .> и <., где знаки меньше / больше указывают на часть opti c, которая имеет нужный нам индекс. (В более сложном сценарии ios с несколькими индексами вы можете использовать <.> для объединения индексов из двух оптик в пары индексов (i,j).)

Вот как мы получаем:

connections .> traversed <. _3

Он по-прежнему пересекает все цены в порядке TypeX, но также переносит индекс из обхода.

Обратите внимание, что setInitPrices на самом деле одна из тех функций, которые легко записать как " все сразу "расчет объектива. map setIndexPrices и рекурсия просто пересекают вложенный список, поэтому они эквивалентны opti c traverse . traverse. Итак, мы можем использовать:

setInitPrices' :: [[Typex]] -> [[Typex]]
setInitPrices' = traverse .> traverse .> connections .> traversed <. _3 .@~ f
  where f i = 2 * fromIntegral i

Наконец, возможно, стоит отметить, что если у вас есть сложный индексированный opti c, например:

a .> b .> c .> d <. e <. f <. g

по неясным причинам (правильная ассоциативность операторы и тот факт, что .> идентичен .), это всегда эквивалентно:

a . b . c .> d <. e . f . g

, и это наиболее распространенный способ записи. Итак, окончательная версия setInitPrices' будет выглядеть так:

setInitPrices' :: [[Typex]] -> [[Typex]]
setInitPrices' = traverse . traverse . connections .> traversed <. _3 .@~ f
  where f i = 2 * fromIntegral i
...