更新嵌套结构的更简洁方法 [英] Cleaner way to update nested structures

查看:53
本文介绍了更新嵌套结构的更简洁方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有以下两个case classes:

Say I have got following two case classes:

case class Address(street: String, city: String, state: String, zipCode: Int)
case class Person(firstName: String, lastName: String, address: Address)

以及以下 Person 类的实例:

and the following instance of Person class:

val raj = Person("Raj", "Shekhar", Address("M Gandhi Marg", 
                                           "Mumbai", 
                                           "Maharashtra", 
                                           411342))

现在如果我想更新 rajzipCode 那么我将不得不这样做:

Now if I want to update zipCode of raj then I will have to do:

val updatedRaj = raj.copy(address = raj.address.copy(zipCode = raj.address.zipCode + 1))

随着嵌套层次的增加,这会变得更加丑陋.是否有更简洁的方法(类似于 Clojure 的 update-in)来更新此类嵌套结构?

With more levels of nesting this gets even more uglier. Is there a cleaner way (something like Clojure's update-in) to update such nested structures?

推荐答案

Zippers

Huet 的 Zipper 为不可变数据结构提供了方便的遍历和变异".Scalaz 为 Stream (scalaz.Zipper) 和 Tree(scalaz.TreeLoc).事实证明,拉链的结构可以从原始数据结构中自动推导出来,其方式类似于代数表达式的符号微分.

Zippers

Huet's Zipper provides convenient traversal and 'mutation' of an immutable data structure. Scalaz provides Zippers for Stream (scalaz.Zipper), and Tree (scalaz.TreeLoc). It turns out that the structure of the zipper is automatically derivable from the original data structure, in a manner that resembles symbolic differentiation of an algebraic expression.

但这对您的 Scala 案例类有何帮助?好吧,Lukas Rytz 最近原型化 scalac 的扩展,它会自动为带注释的案例类创建拉链.我将在此处重现他的示例:

But how does this help you with your Scala case classes? Well, Lukas Rytz recently prototyped an extension to scalac that would automatically create zippers for annotated case classes. I'll reproduce his example here:

scala> @zip case class Pacman(lives: Int = 3, superMode: Boolean = false) 
scala> @zip case class Game(state: String = "pause", pacman: Pacman = Pacman()) 
scala> val g = Game() 
g: Game = Game("pause",Pacman(3,false))

// Changing the game state to "run" is simple using the copy method:
scala> val g1 = g.copy(state = "run") 
g1: Game = Game("run",Pacman(3,false))

// However, changing pacman's super mode is much more cumbersome (and it gets worse for deeper structures):
scala> val g2 = g1.copy(pacman = g1.pacman.copy(superMode = true))
g2: Game = Game("run",Pacman(3,true))

// Using the compiler-generated location classes this gets much easier: 
scala> val g3 = g1.loc.pacman.superMode set true
g3: Game = Game("run",Pacman(3,true)

因此社区需要说服 Scala 团队应该继续这项工作并将其集成到编译器中.

So the community needs to persuade the Scala team that this effort should be continued and integrated into the compiler.

顺便说一句,Lukas 最近发布了一个 Pacman 版本,用户可以通过 DSL 进行编程.不过,看起来他没有使用修改后的编译器,因为我看不到任何 @zip 注释.

Incidentally, Lukas recently published a version of Pacman, user programmable through a DSL. Doesn't look like he used the modified compiler, though, as I can't see any @zip annotations.

在其他情况下,您可能希望根据某种策略(自上而下、自下而上)并基于与结构中某个点的值匹配的规则,对整个数据结构应用一些转换.经典示例是将 AST 转换为一种语言,可能是为了评估、简化或收集信息.Kiama 支持 重写,参见RewriterTests,并观看此视频.这是一个可以激发您食欲的片段:

In other circumstances, you might like to apply some transformation across the entire data structure, according to some strategy (top-down, bottom-up), and based on rules that match against the value at some point in the structure. The classical example is transforming an AST for a language, perhaps to evaluate, simplify, or collect information. Kiama supports Rewriting, see the examples in RewriterTests, and watch this video. Here's a snippet to whet your appetite:

// Test expression
val e = Mul (Num (1), Add (Sub (Var ("hello"), Num (2)), Var ("harold")))

// Increment every double
val incint = everywheretd (rule { case d : Double => d + 1 })
val r1 = Mul (Num (2), Add (Sub (Var ("hello"), Num (3)), Var ("harold")))
expect (r1) (rewrite (incint) (e))

请注意 Kiama 步骤在类型系统之外实现这一点.

Note that Kiama steps outside the type system to achieve this.

这篇关于更新嵌套结构的更简洁方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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