当修改取决于索引时,如何使用镜头修改嵌套自定义数据类型的字段
How to modify fields of a nested custom data type with lenses, when modifications depend on indices
考虑以下因素:
{-# LANGUAGE TemplateHaskell #-}
import Control.Lens
data Typex = Typex
{ _level :: Int
, _coordinate :: (Int, Int)
, _connections :: [(Int,(Int,Int))]
} deriving Show
makeLenses ''Typex
initTypexLevel :: Int -> Int -> Int -> [Typex]
initTypexLevel a b c = [ Typex a (x, y) [(0,(0,0))]
| x <- [0..b], y <- [0..c]
]
buildNestedTypexs :: [(Int, Int)] -> [[Typex]]
buildNestedTypexs pts
= setConnections [ initTypexLevel i y y
| (i,(_,y)) <- zip [0..] pts
]
setConnections :: [[Typex]] -> [[Typex]]
setConnections = ?
如何使用 lenses 修改所有 Typex
中的 connections
以及 [[Typex]] -> [[Typex]]
类型的函数,使得每个 Typex
connections = [(level of Typex being modified +1, (x, y))] where
x,y = 0..(length of next [Typex] in [[Typex]])/2
X和y都需要经过下一个[Typex]的那个长度。如果可能的话,最终的 [Typex] 应该保持不变。所以同一个[Typex]中每个Typex的所有连接都是一样的
setConnections $ buildNestedTypexs [(0,1),(1,1)]
的输出应该是:
[ [ Typex { _level = 0
, _coordinate = (0,0)
, _connections = [(1,(0,0)), (1,(0,1)), (1,(1,0)), (1,(1,1))] }
, Typex { _level = 0
, _coordinate = (0,1)
, _connections = [(1,(0,0)), (1,(0,1)), (1,(1,0)), (1,(1,1))] }
, Typex { _level = 0
, _coordinate = (1,0)
, _connections = [(1,(0,0)), (1,(0,1)), (1,(1,0)), (1,(1,1))] }
, Typex { _level = 0
, _coordinate = (1,1)
, _connections = [(1,(0,0)), (1,(0,1)), (1,(1,0)), (1,(1,1))] }
]
,[ Typex { _level = 1
, _coordinate = (0,0)
, _connections = [(0,(0,0))] }
, Typex { _level = 1
, _coordinate = (0,1)
, _connections = [(0,(0,0))] }
, Typex { _level = 1
, _coordinate = (1,0)
, _connections = [(0,(0,0))] }
, Typex { _level = 1
, _coordinate = (1,1)
, _connections = [(0,(0,0))] }
]]
我想我需要 import Control.Lens.Indexed
但仅此而已,我们将不胜感激。
这是你想要的吗?
{-# LANGUAGE TupleSections #-}
setConnections :: [[Typex]] -> [[Typex]]
setConnections (x:rest@(y:_)) = map (connect y) x : setConnections rest
where connect :: [Typex] -> Typex -> Typex
connect txs tx
= tx & connections .~ (map ((tx ^. level) + 1,) $ txs ^.. traverse.coordinate)
setConnections lst = lst
这不是一个纯粹的镜头解决方案,但我发现作为使用镜头的一般规则,让镜头做所有事情并不总是一个好主意一切 .这只会让事情变得难以编写和理解。
在这里,我在很多地方使用了 "plain Haskell":通过手动递归进行模式匹配以处理连续 x
、y
对 [Typex]
s 和我在第一个 x :: [Typex]
和第二个 y :: [Typex]
中使用 map
到 connect
每个 Typex
。我还使用 map
将新级别添加到坐标列表以生成新的 connections
值。
此处使用的唯一镜头表达式是:
tx & connections .~ (...)
将 tx :: Typex
的 connections
字段替换为新值
tx ^. level
获取当前 tx :: Typex
的级别
txs ^.. traverse.coordinate
获取列表 txs :: [Typex]
和 returns 中所有 Typex
值的 coordinate
字段作为列表 [(Int,Int)]
在我看来,镜头和 "plain Haskell" 之间的这种平衡是处理复杂变换的最佳方式。
考虑以下因素:
{-# LANGUAGE TemplateHaskell #-}
import Control.Lens
data Typex = Typex
{ _level :: Int
, _coordinate :: (Int, Int)
, _connections :: [(Int,(Int,Int))]
} deriving Show
makeLenses ''Typex
initTypexLevel :: Int -> Int -> Int -> [Typex]
initTypexLevel a b c = [ Typex a (x, y) [(0,(0,0))]
| x <- [0..b], y <- [0..c]
]
buildNestedTypexs :: [(Int, Int)] -> [[Typex]]
buildNestedTypexs pts
= setConnections [ initTypexLevel i y y
| (i,(_,y)) <- zip [0..] pts
]
setConnections :: [[Typex]] -> [[Typex]]
setConnections = ?
如何使用 lenses 修改所有 Typex
中的 connections
以及 [[Typex]] -> [[Typex]]
类型的函数,使得每个 Typex
connections = [(level of Typex being modified +1, (x, y))] where
x,y = 0..(length of next [Typex] in [[Typex]])/2
X和y都需要经过下一个[Typex]的那个长度。如果可能的话,最终的 [Typex] 应该保持不变。所以同一个[Typex]中每个Typex的所有连接都是一样的
setConnections $ buildNestedTypexs [(0,1),(1,1)]
的输出应该是:
[ [ Typex { _level = 0
, _coordinate = (0,0)
, _connections = [(1,(0,0)), (1,(0,1)), (1,(1,0)), (1,(1,1))] }
, Typex { _level = 0
, _coordinate = (0,1)
, _connections = [(1,(0,0)), (1,(0,1)), (1,(1,0)), (1,(1,1))] }
, Typex { _level = 0
, _coordinate = (1,0)
, _connections = [(1,(0,0)), (1,(0,1)), (1,(1,0)), (1,(1,1))] }
, Typex { _level = 0
, _coordinate = (1,1)
, _connections = [(1,(0,0)), (1,(0,1)), (1,(1,0)), (1,(1,1))] }
]
,[ Typex { _level = 1
, _coordinate = (0,0)
, _connections = [(0,(0,0))] }
, Typex { _level = 1
, _coordinate = (0,1)
, _connections = [(0,(0,0))] }
, Typex { _level = 1
, _coordinate = (1,0)
, _connections = [(0,(0,0))] }
, Typex { _level = 1
, _coordinate = (1,1)
, _connections = [(0,(0,0))] }
]]
我想我需要 import Control.Lens.Indexed
但仅此而已,我们将不胜感激。
这是你想要的吗?
{-# LANGUAGE TupleSections #-}
setConnections :: [[Typex]] -> [[Typex]]
setConnections (x:rest@(y:_)) = map (connect y) x : setConnections rest
where connect :: [Typex] -> Typex -> Typex
connect txs tx
= tx & connections .~ (map ((tx ^. level) + 1,) $ txs ^.. traverse.coordinate)
setConnections lst = lst
这不是一个纯粹的镜头解决方案,但我发现作为使用镜头的一般规则,让镜头做所有事情并不总是一个好主意一切 .这只会让事情变得难以编写和理解。
在这里,我在很多地方使用了 "plain Haskell":通过手动递归进行模式匹配以处理连续 x
、y
对 [Typex]
s 和我在第一个 x :: [Typex]
和第二个 y :: [Typex]
中使用 map
到 connect
每个 Typex
。我还使用 map
将新级别添加到坐标列表以生成新的 connections
值。
此处使用的唯一镜头表达式是:
tx & connections .~ (...)
将tx :: Typex
的connections
字段替换为新值tx ^. level
获取当前tx :: Typex
的级别
txs ^.. traverse.coordinate
获取列表txs :: [Typex]
和 returns 中所有Typex
值的coordinate
字段作为列表[(Int,Int)]
在我看来,镜头和 "plain Haskell" 之间的这种平衡是处理复杂变换的最佳方式。