当修改取决于索引时,如何使用镜头修改嵌套自定义数据类型的字段 [英] How to modify fields of a nested custom data type with lenses, when modifications depend on indices

查看:104
本文介绍了当修改取决于索引时,如何使用镜头修改嵌套自定义数据类型的字段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑以下几点:

{-# 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 = ?

我该如何使用镜头在所有Typex中使用类型[[Typex]] -> [[Typex]]的功能来修改connections,使得每个Typex

How can I uses lenses to modify the connections in allTypexs with a function of type [[Typex]] -> [[Typex]] in such a way that in each 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的所有连接都是相同的.

X and y both need to go through that length of the next [Typex]. The final [Typex] should be left unchanged if possible. So all the connections of each Typex in the same [Typex] are the same.

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,但仅此而已,所以所有帮助都值得赞赏.

I suppose I'll need to import Control.Lens.Indexed but that's about it so all help is appreciated.

推荐答案

这是您想要的吗?

{-# 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

这不是一个纯粹的镜头解决方案,但我发现,作为使用镜头的一般规则,让镜头执行一切并非总是一个好主意.这只会使事情难以编写且难以理解.

This isn't a pure lens solution, but I find that as a general rule when working with lenses, it's not always a good idea to get the lenses to do everything. It just makes things difficult to write and hard to understand.

在这里,我在很多地方都使用过普通Haskell":通过手动递归进行模式匹配,以处理连续[Typex]对的xy对,并且我已经使用过map到第一个x :: [Typex]中的每个Typex和第二个y :: [Typex]中的每个Typex.我还使用map将新级别添加到坐标列表中,以生成新的connections值.

Here, I've used "plain Haskell" in a lot of places: to pattern matching with a manual recursion to process pairs x,y of consecutive [Typex]s and I've used map to connect each Typex in the first x :: [Typex] with the second y :: [Typex]. I've also used map to add the new level to the coordinate list to generate the new connections value.

这里使用的唯一镜头表情是:

The only lens expressions used here are:

  • tx & connections .~ (...)用新值替换tx :: Typexconnections字段
  • tx ^. level会获取当前tx :: Typex
  • 的级别
  • txs ^.. traverse.coordinate会获取列表txs :: [Typex]中所有Typex值的coordinate字段,并将它们作为列表[(Int,Int)]
  • 返回
  • tx & connections .~ (...) which replaces the connections field of tx :: Typex with a new value
  • tx ^. level which fetches the level of the current tx :: Typex
  • txs ^.. traverse.coordinate which fetches the coordinate fields of all Typex values in the list txs :: [Typex] and returns them as a list [(Int,Int)]

我认为,镜头和普通Haskell"之间的这种平衡是处理复杂转换的最佳方法.

In my opinion, this sort of balance between lenses and "plain Haskell" is the best way of dealing with complex transformations.

这篇关于当修改取决于索引时,如何使用镜头修改嵌套自定义数据类型的字段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆