I can't get the types in the last function to line up. Point is to set the all price Doubles in connections with a function that depends only on the index of the 3-tuple. The original Double value in the tuple can be discarded.
{-# 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
You are probably looking for:
where setIndexPrices :: Typex -> Typex
setIndexPrices tx = tx & connections .> traversed <. _3 .@~ f
f i = 2 * fromIntegral i
Here, .@~
is the operator version of iset
, and .>
and <.
are variants of the composition operator .
used to combine indexed optics.
If you consider the simpler unindexed optic:
connections . traverse . _3
This optic takes a TypeX
, focuses on its _connections
fields, traverses the list of connections, and focuses on the third field (the price) of each connection. The result is an optic that traverses all the prices in the TypeX
in order.
To index this optic, we need to "upgrade" the unindexed traverse
to the indexed traversed
. Then, we want to use the index-preserving composition operators .>
and <.
where the less/greater than signs point to the part of the optic that has the index we want. (In more complicated scenarios with multiple indexes, you can use <.>
to combine indexes from two optics into index pairs (i,j)
.)
That's how we get:
connections .> traversed <. _3
It still traverses all the prices in the TypeX
in order, but it also carries around the index from the traversal.
Note that setInitPrices
is actually one of those functions that's easily written as an "all at once" lens computation. The map setIndexPrices
and recursion just traverse the nested list, so they're the equivalent of the optic traverse . traverse
. So, we can use:
setInitPrices' :: [[Typex]] -> [[Typex]]
setInitPrices' = traverse .> traverse .> connections .> traversed <. _3 .@~ f
where f i = 2 * fromIntegral i
Finally, it's maybe worth noting that if you have a complicated indexed optic like:
a .> b .> c .> d <. e <. f <. g
for obscure reasons (right associativity of the operators and the fact that .>
is identical to .
) this is always equivalent to:
a . b . c .> d <. e . f . g
and this is the more common way to write it. So, the final version of setInitPrices'
would be:
setInitPrices' :: [[Typex]] -> [[Typex]]
setInitPrices' = traverse . traverse . connections .> traversed <. _3 .@~ f
where f i = 2 * fromIntegral i