Возврат различных типов массивов из лямбда-выражения в F#

у меня есть список записей

type Item = { Color : string; Size : int}
let itemList = [{Color="Red"; Size=1};
                {Color="Green"; Size=2};
                {Color="Blue"; Size=3};]

Я хочу превратить свой список записей в массив значений, таких как [|"Красный";"Зеленый";"Синий"|] или [|1;2;3|]

Я могу попасть туда вот так

type ItemType =
| Color of string
| Size of int

type ItemEnum =
| C
| S

let GetProp x y =
match x with
| C -> List.toArray y |> Array.map(fun x -> ItemType.Color(x.Color))
| S -> List.toArray y |> Array.map(fun x -> ItemType.Size(x.Size))

но когда я вызываю GetProp S itemList, я возвращаю [|Size 1; Размер 2; Размер 3|]. Полезно, но не совсем то, что я ищу.

Я пробовал следующее

let GetProp2 x y : 'a[] =
match x with
| Color -> List.toArray y |> Array.map(fun x -> x.Color)
| Size -> List.toArray y |> Array.map(fun x -> x.Size)

но ему не нравятся два разных типа возврата.

Я открыт для предложений о различных (более функциональных?) способах сделать это и был бы признателен за ваш вклад.


person RobRolls    schedule 19.12.2009    source источник


Ответы (3)


Пользовательский вариантный тип действительно подходит для этого (и вообще везде, где вам нужен тип «либо X, либо Y»). Однако, как определено, ваша функция выглядит так, как будто она может возвращать массив, в котором смешаны Color и Size, но на практике кажется, что вы хотите, чтобы она возвращала только одно или другое. Если да, то это лучше всего отражается в типах:

type Items =
| Colors of string[]
| Sizes of int[]

let GetProp x ys =
match x with
| C -> Colors [| for y in ys -> y.Color |]
| S -> Sizes [| for y in ys -> y.Size |]

Кстати, есть ли какая-то конкретная причина, по которой вы используете здесь массив для возвращаемого типа, а не обычную ленивую последовательность (seq)?

person Pavel Minaev    schedule 19.12.2009
comment
массив - это тип аргумента, требуемый внешней библиотекой, которую я использую дальше. Как мне перейти от списка записей к последовательности определенного значения? - person RobRolls; 19.12.2009
comment
Любой список уже является последовательностью, как и любой массив. В терминах .NET seq — это IEnumerable<T>. Если вам нужно создать массив или список из любой случайной последовательности (и, возможно, ленивой), то Seq.toArray и Seq.toList сделают свое дело. - person Pavel Minaev; 19.12.2009

Вы можете использовать активные шаблоны, чтобы увидеть, как ваши данные формируют несколько точек зрения:

let (|AsColor|) (v: Item list) = [| for i in v -> i.Color |];;

let (|AsSize|) (v: Item list) = [| for i in v -> i.Size |];;

match itemList,itemList with
  |AsColor ca, AsSize sa -> printfn "%A; %A" ca sa;;
person ssp    schedule 19.12.2009
comment
Я еще не подвергался воздействию активного паттерна. Интересно, спасибо. - person RobRolls; 19.12.2009

Гаджет Go Go Array Comprehension!

> [| for a in itemList do yield a.Size |];;
val it : int [] = [|1; 2; 3|]
> [| for a in itemList do yield a.Color |];;
val it : string [] = [|"Red"; "Green"; "Blue"|]

Вам не нужна промежуточная структура данных ItemType или ItemEnum.

person Juliet    schedule 19.12.2009
comment
Это ему не поможет, так как он пытается написать одну функцию, которая возвращает массивы различных типов элементов в зависимости от ее аргументов. - person Pavel Minaev; 19.12.2009