F#修改并返回

Li *_*oyi 0 f# immutability

type Tag(Kids) =
    member this.Kids = Kids

    static member (-) (this: Tag, that: list<obj>) = 
        Tag(that::this.Kids)
Run Code Online (Sandbox Code Playgroud)

此代码的要点是基于现有对象构造新对象,但修改对象上的一个(或多个)字段.基本上,它是thing.setX(...)mutator方法的代理,除了使用不可变数据.

它看起来非常丑陋和冗长,我确信在保持数据的不变性的同时必须有更好的方法,但我还没弄清楚如何.这有什么语法上很好的方法吗?

编辑:为了清楚起见,我还在层次结构中有其他类:

type HTMLTag(s, Classes, Kids, Styles) = 
    inherit Tag(Kids)

    member this.NominalTag = s
    member this.Classes = Classes
    member this.Styles: list<String * String> = Styles

    static member (-) (this: HTMLTag, that: list<obj>) = 
        HTMLTag(this.NominalTag, this.Classes, that::this.Kids, this.Styles)
Run Code Online (Sandbox Code Playgroud)

除了它非常冗长之外,-函数的"复制与修改"的东西完全是非泛型的:即使我每次都做同样的事情(复制w /修改为同一个变量)我还要重写整个事情,这不是很好.

我发现非常讨厌的一件事是变异非常简单:

static member (-) (this: Tag, that: list<obj>) = 
    this.Kids = that :: this.Kids
    this
Run Code Online (Sandbox Code Playgroud)

但我试图尽可能保持一切不变

Dan*_*iel 6

复制和更新记录表达式[MSDN]旨在处理这种确切的情况.如果您可以使用记录类型,则可以执行此操作

type Tag = 
  { NominalTag : obj
    Classes : obj
    Kids : list<obj>
    Styles : list<String * String> }
  static member (-) (this: Tag, that: list<obj>) = 
    { this with Kids = this.Kids @ that }
Run Code Online (Sandbox Code Playgroud)

此代码的编译形式与您的代码几乎完全相同.

顺便说一句,(-)操作员被用来追加是奇怪的......但我认为这是一个人为的例子.

UPDATE

现在您已经更新了问题,我对您想要做的事感到困惑.如果你想返回一个新对象,我看不到变异如何帮助你.

更具功能性的方法(vs继承)是分离数据和行为,数据是记录和模块中分组的行为功能.如果希望跨类型共享行为,请使用接口.记录可以实现接口.