Reputation: 37
Say I've made a new data type as follows:
data Typex = Typex {
level :: Int,
coordinate :: (Int, Int),
connections :: [(Int,(Int,Int),Double)] -- edited to be a tuple
} deriving Show
I want to modify the connections from an upper level where I use [[TypeX]]
. Do I need nested loops, fmap and a functor instance for my custom type or what would you suggest?
Upvotes: 3
Views: 174
Reputation: 80714
First, describe how you want to modify a single connection. Give it a name:
modConnection (i, (j, k), d) = (i + 42, (j*5, k), d)
To update a whole list of connections, use map
:
modConnections cons = map modConnection cons
To update a field in the record, use the Haskell record update syntax:
modTypeX :: TypeX -> TypeX
modTypeX tx = tx { connections = modConnections (connections tx) }
To update a whole list of these records, use map
again:
modTypeXList txs = map modTypeX txs
And finally, to update a whole list of these lists, use map
once again:
modTypeXListList txs = map modTypeXList txs
Of course, if you don't want to give a name to every intermediate function, you don't have to, you can do everything inline:
modTypeXListList = map . map $ \tx -> tx { connections = map modConnection (connections tx) }
Upvotes: 2
Reputation: 120711
You probably want lenses.
{-# LANGUAGE TemplateHaskell #-}
import Control.Lens
data Typex = Typex
{ _level :: Int
, _coordinate :: (Int, Int)
, _connections :: [(Int,(Int,Int),Double)]
} deriving Show
makeLenses ''Typex
main :: IO ()
main = print $ [[Typex 0 (0,0) []]
,[Typex 1 (1,1) [], Typex 1 (2,2) []]
,[]]
& ix 1 . ix 0 . connections
%~ ((9,(9,9),pi):)
In this example, the the nested list is indexed (ix
) into the head of the middle element, in that Typex
value focused on the connections
field, and there the element (9,(9,9),pi)
prepended. Result:
[[Typex {_level = 0, _coordinate = (0,0), _connections = []}],[Typex {_level = 1, _coordinate = (1,1), _connections = [(9,(9,9),3.141592653589793)]},Typex {_level = 1, _coordinate = (2,2), _connections = []}],[]]
Upvotes: 4