按值修改Haskell嵌套记录
假设我有一个嵌套结构,如下所示:按值修改Haskell嵌套记录,haskell,records,template-haskell,lenses,Haskell,Records,Template Haskell,Lenses,假设我有一个嵌套结构,如下所示: data Bar = Bar { _id :: Integer, _bars :: [Bar] } data Foo = Foo { _bars :: [Bar] } 我有一个Foo和一堆条以及各种ids: foo = Foo [Bar 1 [Bar 2], Bar 3 [Bar 4, Bar 5]] 我如何使用镜头修改foo,使Bar 5变成Bar 6 我知道我使用fclabels来做这样的事情: mkLabel ''Foo mkLabel ''Bar m
data Bar = Bar { _id :: Integer, _bars :: [Bar] }
data Foo = Foo { _bars :: [Bar] }
我有一个Foo
和一堆条
以及各种id
s:
foo = Foo [Bar 1 [Bar 2], Bar 3 [Bar 4, Bar 5]]
我如何使用镜头修改foo
,使Bar 5
变成Bar 6
我知道我使用fclabels
来做这样的事情:
mkLabel ''Foo
mkLabel ''Bar
modify bars (\bars -> ...) foo
但条可以无限嵌套。如何使用指定的ID定位和修改
栏
?是的,镜头
可以做到这一点。该模块包含用于“废弃样板文件”式编程的工具,具有类似于条的自相似结构。这个想法非常简单:解释如何找到节点的直接子节点(通过编写遍历'a
),然后库递归地将该遍历应用于整个结构
{-# LANGUAGE TemplateHaskell #-}
import Control.Lens
data Bar = Bar { _lbl :: Int, _bars :: [Bar] } deriving (Show)
makeLenses ''Bar
instance Plated Bar where
plate = bars.traverse
fiveToSix :: Bar -> Bar
fiveToSix = transform go
where go bar
| bar^.lbl == 5 = bar & lbl .~ 6
| otherwise = bar
(如果您不想自己实现plate
,可以派生实例并将其保留为空。)
接受修改单个节点并将其应用于整个结构的函数
{-# LANGUAGE TemplateHaskell #-}
import Control.Lens
data Bar = Bar { _lbl :: Int, _bars :: [Bar] } deriving (Show)
makeLenses ''Bar
instance Plated Bar where
plate = bars.traverse
fiveToSix :: Bar -> Bar
fiveToSix = transform go
where go bar
| bar^.lbl == 5 = bar & lbl .~ 6
| otherwise = bar
使用您问题中的示例:
ghci> let bars = [Bar 1 [Bar 2 []], Bar 3 [Bar 4 [], Bar 5 []]]
ghci> map fiveToSix bars
[Bar 1 [Bar 2 []], Bar 3 [Bar 4 [], Bar 6 []]]
作为另一个示例,对于funzies,让我们使用将所有条5
从条中拉出
fives :: Bar -> [Bar]
fives = toListOf $ cosmos.filtered (views lbl (== 5))
您想根据标签的值或此树中的位置来更新它吗?如果有多个Bar 5
,您预计会发生什么?似乎transformOn
和transformOnOf
将允许直接处理Foo
值。@danidiaz Yep,transformOn
基本上只是在给定镜头内运行transform
:transformOn sg=over s(transform g)