简体   繁体   English

F# 在可区分联合内提取值而不匹配

[英]F# Extract value within Discriminated Union without matching

I have the following Discriminated Union (DU) declaration:我有以下歧视联盟 (DU) 声明:

type Book =
    | Dictionary of string[]
    | Novel of int[]
    | Comics of bool[]

An example:一个例子:

let x = Dictionary [|"a"; "b"|]

How can I extract the length of the array inside without doing pattern matching and without caring about the data type of the array (in this case: string , int , bool ).如何在不进行模式匹配且不关心数组的数据类型(在本例中为: stringintbool )的情况下提取内部数组的长度。 Note: I have no control over the DU declaration;注意:我无法控制 DU 声明; as a result, I can't write new member method within Book , like getArrayLength()结果,我无法在Book中编写新的成员方法,例如getArrayLength()

Of course, we can do it in some way as followed:当然,我们可以通过以下方式做到这一点:

match x with
| Dictionary (x: _[]) -> x |> Array.length
| Novel (x: _[]) -> x |> Array.length
| Comics (x: _[]) -> x |> Array.length

But typing x |> Array.length a lot is incovenient.但是输入x |> Array.length很多是不方便的。 This is a simple example, but we can think of a general problem:这是一个简单的例子,但我们可以想到一个普遍的问题:

type Animal =
   | Dog of DogClass
   | Cat of CatClass
   | Cow of CowClass
   ...

... and DogClass , CatClass , etc. may share something. ...和DogClassCatClass等可能会分享一些东西。 We want to get that shared thing .我们想得到那个共享的东西 Eg those classes inherit from AnimalClass , within which there is countLegs() method.例如,这些类继承自AnimalClass ,其中有countLegs()方法。 Suppsed there are many animals, pattern matching for all of them while the code block after -> is almost the same.假设有很多动物,所有动物的模式匹配,而->之后的代码块几乎相同。 I love the principle DRY (Don't Repeat Yourself).我喜欢DRY原则(不要重复自己)。

Is there any convenient way to tackle such problem?有什么方便的方法来解决这样的问题吗?

== ==

EDITED 21.10.2019 2019 年 10 月 21 日编辑

I was also looking for some syntax like:我也在寻找一些语法,例如:

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."

I think this still follows the spirit of matching, but seem like this approach is not supported.我认为这仍然遵循匹配的精神,但似乎不支持这种方法。

Realistically, there's no getting around pattern matching here.实际上,这里没有绕过模式匹配。 DUs were, in a way, built for it.在某种程度上,DU 就是为此而生的。 Since you don't control the type, you can always add a type extension:由于您不控制类型,因此您始终可以添加类型扩展:

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

Though it's also equally valid to define a Book module with a length function on it if you prefer that:尽管如果您愿意,也可以在其上定义length function 的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

But you'll need to write a pattern match expression on the Book type at least once.但是您需要在Book类型上至少编写一次模式匹配表达式。 The fact that every case is made up of data that all has the same property doesn't really help the fact that you need to still identify every case individually.每个案例都由具有相同属性的数据组成这一事实并不能真正帮助您仍然需要单独识别每个案例。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM