调整区分联合对象的值

时间:2021-06-28 23:17:11

So, yet another discriminated union question :-)

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

Assume I have a discriminated union like so:-

假设我有一个像这样的歧视联盟: -

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

I would like to be able to use a function, appendStringToFoo, as follows:-

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

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

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

Where hiya = A("hiya") and yoyo = D("yoyo").

hiya = A(“hiya”)和yoyo = D(“yoyo”)。

Obviously, I'd also go on to write separate functions appendIntToFoo, appendCharToFoo, etc.

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

So, effectively, a function similar to:-

所以,实际上,一个类似的功能: -

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

Which doesn't seem possible.

这似乎不可能。

I do not want to do the following if I can avoid it:-

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

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

As that means I'd have to re-write this code every time I added a new union case.

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

Any ideas?

1 个解决方案

#1


You have to do the thing you don't want to do.

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

An alternative would be along the lines of

另一种选择是沿着这条线

  • abstract class Foo
  • 抽象类Foo

  • abstract class StringyFoo : Foo { void AppendString(string); string S; }
  • abstract class StringyFoo:Foo {void AppendString(string);串S; }

  • class A : StringyFoo
  • A类:StringyFoo

  • class D : StringyFoo
  • D类:StringyFoo

  • abstract class IntyFoo : Foo
  • 抽象类IntyFoo:Foo

  • class B : IntyFoo
  • B级:IntyFoo

which potentially avoids 'fixing up appendString() each time you add a new token type', but I think that for a lexer (where Foo=Token) you'll be happier overall with the DU.

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

In general with lexing/parsing, whether you use class hierarchies and the Visitor pattern, or you use algebraic data types, you always must write N*M code for N features and M subtypes; there's no avoiding it, so don't bother trying to find cute tricks to try to avoid it, it only leads to misery.

通常使用lexing / parsing,无论是使用类层次结构还是访问者模式,还是使用代数数据类型,您总是必须为N个特征和M个子类型编写N * M代码;没有避免它,所以不要试图找到可爱的技巧来试图避免它,它只会导致痛苦。

#1


You have to do the thing you don't want to do.

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

An alternative would be along the lines of

另一种选择是沿着这条线

  • abstract class Foo
  • 抽象类Foo

  • abstract class StringyFoo : Foo { void AppendString(string); string S; }
  • abstract class StringyFoo:Foo {void AppendString(string);串S; }

  • class A : StringyFoo
  • A类:StringyFoo

  • class D : StringyFoo
  • D类:StringyFoo

  • abstract class IntyFoo : Foo
  • 抽象类IntyFoo:Foo

  • class B : IntyFoo
  • B级:IntyFoo

which potentially avoids 'fixing up appendString() each time you add a new token type', but I think that for a lexer (where Foo=Token) you'll be happier overall with the DU.

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

In general with lexing/parsing, whether you use class hierarchies and the Visitor pattern, or you use algebraic data types, you always must write N*M code for N features and M subtypes; there's no avoiding it, so don't bother trying to find cute tricks to try to avoid it, it only leads to misery.

通常使用lexing / parsing,无论是使用类层次结构还是访问者模式,还是使用代数数据类型,您总是必须为N个特征和M个子类型编写N * M代码;没有避免它,所以不要试图找到可爱的技巧来试图避免它,它只会导致痛苦。