【问题标题】:Adjusting value of a discriminated union object调整可区分联合对象的值
【发布时间】:2009-04-08 22:23:38
【问题描述】:

所以,又是一个受歧视的工会问题 :-)

假设我有一个像这样的有区别的联合:-

type Foo =
  | A of string
  | B of int
  | C of char
  | D of string

我希望能够使用一个函数,appendStringToFoo,如下:-

let someVal = A("hi")
let anotherVal = D("yo")

let hiya = someVal |> appendStringToFoo "ya"
let yoyo = anotherVal |> appendStringToFoo "yo"

hiya = A("hiya") 和 yoyo = D("yoyo")。

显然,我还会继续编写单独的函数 appendIntToFoo、appendCharToFoo 等。

所以,实际上,一个类似于以下的函数:-

let appendStringToFoo str fooValue =
  fooValue(fooValue.Value + str)

这似乎不可能。

如果可以避免的话,我不想做以下事情:-

let appendStringToFoo str fooValue =
    match fooValue with
    | A(originalStr) -> A(originalStr + str)
    | D(originalStr) -> D(originalStr + str)

因为这意味着我每次添加新的联合案例时都必须重新编写这段代码。

有什么想法吗?

【问题讨论】:

  • 您希望 appendStringToFoo "x" (B(42)) 有什么行为?总的来说,这对我来说很奇怪,你真正想做什么(什么是 Foo/A/B)?
  • 一般来说,“每次你添加一个新的联合案例”你必须重写世界上所有使用那个联合类型的代码。这是使用可区分联合和使用类层次结构之间的权衡。
  • 这是词法分析器的一部分;我正在从字符构造一个字符串,该字符串被放置在令牌的可区分联合表示中。
  • 无论如何我已经重构了这个(是的,它确实有味道!)。在回答您的问题时,我曾打算在这种情况下导致某种异常;然而,经过反思,它似乎相当不安全。现在我想再次匹配 'a -> DiscrimUnion 的问题......!

标签: f#


【解决方案1】:

你必须做你不想做的事情。

另一种方法是

  • 抽象类 Foo
  • 抽象类 StringyFoo : Foo { void AppendString(string);字符串 S; }
  • A 类:StringyFoo
  • D 类:StringyFoo
  • 抽象类 IntyFoo : Foo
  • B 类:IntyFoo

这可能会避免“每次添加新标记类型时都修复 appendString()”,但我认为对于词法分析器(其中 Foo=Token),你会更喜欢 DU。

一般而言,对于词法分析/解析,无论您使用类层次结构和访问者模式,还是使用代数数据类型,您总是必须为 N 个特征和 M 个子类型编写 N*M 代码;没有办法避免,所以不要费心寻找可爱的技巧来避免它,它只会导致痛苦。

【讨论】:

  • 中肯的建议。我想我只是要通过艰苦的方式学习很多这些东西......!
猜你喜欢
  • 1970-01-01
  • 2017-12-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多