F#在不匹配的情况下提取可区分联合内的值
F# Extract value within Discriminated Union without matching
我有以下歧视联盟 (DU) 声明:
type Book =
| Dictionary of string[]
| Novel of int[]
| Comics of bool[]
一个例子:
let x = Dictionary [|"a"; "b"|]
如何在不进行模式匹配且不关心数组的数据类型的情况下提取 中数组的长度(在本例中:string
, int
、bool
)。注意:我无法控制 DU 声明;结果,我无法在 Book
中编写新的成员方法,例如 getArrayLength()
当然,我们可以通过以下方式实现:
match x with
| Dictionary (x: _[]) -> x |> Array.length
| Novel (x: _[]) -> x |> Array.length
| Comics (x: _[]) -> x |> Array.length
但是输入很多 x |> Array.length
很不方便。这是一个简单的例子,但是我们可以想到一个通用的问题:
type Animal =
| Dog of DogClass
| Cat of CatClass
| Cow of CowClass
...
...和DogClass
、CatClass
等可能会分享一些东西。我们想要获得 那个共享的东西 。例如。那些 类 继承自 AnimalClass
,其中有 countLegs()
方法。假设有很多动物,对所有动物进行模式匹配,而 ->
之后的代码块几乎相同。我喜欢原则 DRY
(不要重复自己)。
有什么方便的方法可以解决这个问题吗?
==
2019 年 10 月 21 日编辑
我也在寻找像这样的语法:
let numEles =
match x with
| _ (arr: _[]) -> x |> Array.Length
| _ -> failwith "No identifiers with fields as Array."
let numLegs =
match anAnimall with
| _ (animal: ?> Animal) -> animal.countLegs()
| _ -> failwith "Can't count legs because of not being an animal."
我觉得还是遵循了匹配的精神,但是好像不支持这种做法
实际上,这里无法绕过模式匹配。在某种程度上,DU 就是为此而建造的。由于您无法控制类型,因此您可以随时添加类型扩展:
type Book with
member this.Length =
match this with
| Dictionary d -> d.Length
| Novel n -> n.Length
| Comics c -> c.Length
let x = Dictionary [|"a"; "b"|]
printfn "%d" x.Length // Prints 2
尽管如果您愿意,定义一个带有 length
函数的 Book
模块也同样有效:
module Book =
let length b =
match b with
| Dictionary d -> d.Length
| Novel n -> n.Length
| Comics c -> c.Length
let x = Dictionary [|"a"; "b"|]
printfn "%d" (x |> Book.length) // prints 2
但是您至少需要在 Book
类型上编写一次模式匹配表达式。每个案例都由具有相同 属性 的数据组成这一事实并不能真正帮助您仍然需要单独识别每个案例。
我有以下歧视联盟 (DU) 声明:
type Book =
| Dictionary of string[]
| Novel of int[]
| Comics of bool[]
一个例子:
let x = Dictionary [|"a"; "b"|]
如何在不进行模式匹配且不关心数组的数据类型的情况下提取 中数组的长度(在本例中:string
, int
、bool
)。注意:我无法控制 DU 声明;结果,我无法在 Book
中编写新的成员方法,例如 getArrayLength()
当然,我们可以通过以下方式实现:
match x with
| Dictionary (x: _[]) -> x |> Array.length
| Novel (x: _[]) -> x |> Array.length
| Comics (x: _[]) -> x |> Array.length
但是输入很多 x |> Array.length
很不方便。这是一个简单的例子,但是我们可以想到一个通用的问题:
type Animal =
| Dog of DogClass
| Cat of CatClass
| Cow of CowClass
...
...和DogClass
、CatClass
等可能会分享一些东西。我们想要获得 那个共享的东西 。例如。那些 类 继承自 AnimalClass
,其中有 countLegs()
方法。假设有很多动物,对所有动物进行模式匹配,而 ->
之后的代码块几乎相同。我喜欢原则 DRY
(不要重复自己)。
有什么方便的方法可以解决这个问题吗?
==
2019 年 10 月 21 日编辑
我也在寻找像这样的语法:
let numEles =
match x with
| _ (arr: _[]) -> x |> Array.Length
| _ -> failwith "No identifiers with fields as Array."
let numLegs =
match anAnimall with
| _ (animal: ?> Animal) -> animal.countLegs()
| _ -> failwith "Can't count legs because of not being an animal."
我觉得还是遵循了匹配的精神,但是好像不支持这种做法
实际上,这里无法绕过模式匹配。在某种程度上,DU 就是为此而建造的。由于您无法控制类型,因此您可以随时添加类型扩展:
type Book with
member this.Length =
match this with
| Dictionary d -> d.Length
| Novel n -> n.Length
| Comics c -> c.Length
let x = Dictionary [|"a"; "b"|]
printfn "%d" x.Length // Prints 2
尽管如果您愿意,定义一个带有 length
函数的 Book
模块也同样有效:
module Book =
let length b =
match b with
| Dictionary d -> d.Length
| Novel n -> n.Length
| Comics c -> c.Length
let x = Dictionary [|"a"; "b"|]
printfn "%d" (x |> Book.length) // prints 2
但是您至少需要在 Book
类型上编写一次模式匹配表达式。每个案例都由具有相同 属性 的数据组成这一事实并不能真正帮助您仍然需要单独识别每个案例。