haskell - 按值修改 Haskell 嵌套记录

标签 haskell records template-haskell lenses

假设我有一个嵌套结构如下:

data Bar = Bar { _id :: Integer, _bars :: [Bar] }
data Foo = Foo { _bars :: [Bar] }

我有一个 Foo有一堆 Bars与各种id年代:
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

但是条形可以无限嵌套。如何定位和修改 Bar有指定的ID?

最佳答案

是的,lens可以做到这一点。 Control.Lens.Plated 模块包含用于“废弃您的样板”式编程的工具,具有自相似结构,如您的 Bar .这个想法非常简单:你解释了如何找到一个节点的直接子节点(通过编写 Traversal' a a ),然后库递归地将该遍历应用于整个结构。

{-# LANGUAGE TemplateHaskell #-}

import Control.Lens    

data Bar = Bar { _lbl :: Int, _bars :: [Bar] } deriving (Show)

makeLenses ''Bar

instance Plated Bar where
    plate = bars.traverse

(如果您不想自己实现 plate,可以推导出 Data 并将 instance 留空。)

transform :: Plated a => (a -> a) -> a -> a 接受一个修改单个节点并将其应用于整个结构的函数。
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,让我们使用 cosmos 拉所有Bar 5来自 Bar .
fives :: Bar -> [Bar]
fives = toListOf $ cosmos.filtered (views lbl (== 5))

关于haskell - 按值修改 Haskell 嵌套记录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42516064/

相关文章:

haskell - 如何使用 Template Haskell、Aeson 和类型系列自动派生 FromJSON

haskell - Haskell 中的推导是如何进行的?

haskell - 在 Haskell 中隐藏状态 - Lazyset

haskell - 有没有一种很好的方法来编写这个涉及单例数据类型的 Template Haskell 代码?

templates - 从模板 Haskell 代码生成最终代码

php - 如何根据特定字段的值在一定时间后删除记录?

haskell - 上下文为 `Prism' 的 `ctx` s a` 是什么?

haskell - Haskell数据结构生成图

f# - 如何在 F# 中更新 <T> 类型列表中的值?

mysql - 在 SELECT 上为日历日期范围创建重复记录