当类型聚合其他类型时,如何避免样板代码

Gre*_*egC 2 f#

我想模仿我的域名.我从聚合开始:

type Tree() =
  member x.Plant = ...
  member x.Trim = ...
  member x.Uproot = ...

type FruitTree(tree : Tree) =
  member x.Trim = ... // redefine
  member x.PickFruit = ...
  // and also make available members from Tree type without following boilerplate code to forward calls
  member x.Plant = tree.Plant
  member x.Uproot = tree.Uproot
Run Code Online (Sandbox Code Playgroud)

如何在不必拼出它们的情况下从聚合对象中获取成员?

编辑

继承时,继承类型的成员位于新创建的类型的公共表面中.有没有办法在不暴露实际字段的情况下使用聚合类型的容器获得类似的效果?

Tom*_*cek 6

有两种方法可以做到这一点,这实际上取决于你实际做了什么 - 树木和果树的例子永远不会是真实的.看看Scott Wlaschin的Domain Driven Design材料,它们是对这些选项的一个很好的总结.

在F#中,人们通常会避免继承而是使用组合.你可以写一个看起来像这样的包装器:

type FruitTree(tree : Tree) =
  member x.Tree = tree  // Expose the wrapped tree
  member x.PickFruit =  // Add other functionality here
Run Code Online (Sandbox Code Playgroud)

这可能在某些情况下有效.如果您正在寻找更实用的解决方案,则应将数据与操作分开.然后你可以定义看起来像这样的数据结构:

type Tree = 
  | Ordinary of int     // Some data about tree - say, number of branches
  | Fruit of Tree * int // Annotates another tree with number of fruits
Run Code Online (Sandbox Code Playgroud)

然后你可以编写在树上操作的函数:

let rec trim tree =
  match tree with
  | Ordinary(n) -> Ordinary(n-1) // Remove one branch from the tree
  | Fruit(t, f) -> Fruit(trim t, f) // Recursively apply on the wrapped tree
Run Code Online (Sandbox Code Playgroud)

也就是说,你真的需要一个更具体的例子来得到一个有用的答案..