F # Извлечь значение в Дискриминационном Союзе без сопоставления - PullRequest
0 голосов
/ 16 октября 2019

У меня есть следующее объявление Дискриминационного союза (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 (не повторяй себя).

Есть ли какой-нибудь удобный способ решения такой проблемы?

==

РЕДАКТИРОВАНИЕ 21.10.2019

Я также искал некоторый синтаксис, такой как:

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

Я думаю, что это все еще следует духу соответствия, но кажется, что этот подход не поддерживается.

1 Ответ

2 голосов
/ 16 октября 2019

Реально, здесь нет возможности обойти шаблон. 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

Хотя также одинаково правильно определить модуль Book с функцией length, если вы предпочитаете:

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. Тот факт, что каждый случай состоит из данных, которые имеют одно и то же свойство, на самом деле не помогает тому факту, что вам все равно нужно идентифицировать каждый случай индивидуально.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...