Ладно, вот странный вопрос. Я использую FSharp.Data.SqlClient
для получения записей из нашей базы данных. Записи, которые он выводит, имеют несколько полей, которые являются типами опций. Мне нужно отфильтровать записи, в которых ЛЮБОЙ из типов опций равен None, и создать новые записи, в которых поля известны. Ниже приведен пример того, о чем я говорю. Чтобы решить эту проблему, я создал функцию фильтра recordFilter
, которая возвращает нужный мне тип в случае, если все типы Option<'T>
содержат значение, и None
, когда они не содержат.
Мой вопрос заключается в том, можно ли создать функцию, которая просто автоматически проверяет все поля Option<'T>
в записи на наличие значения. Я предполагаю, что для перебора полей записи потребуется какое-то отражение. Я предполагаю, что это невозможно, но я хотел бросить это там, если я ошибаюсь.
Если этот подход является идиоматическим, то я был бы рад это услышать. Я просто хотел убедиться, что не упустил более элегантное решение. Возможности F# постоянно меня удивляют.
Моя мотивация заключается в том, что я имею дело с записями с десятками полей, которые имеют тип Option<'T>
. Раздражает необходимость писать массивный оператор match...with
, как это делаю я в этом примере. Когда это всего несколько полей, это нормально, когда это 30+ полей, это раздражает.
type OptionRecord = {
Id: int
Attr1: int option
Attr2: int option
Attr3: int option
Attr4: int option
Attr5: int option
Attr6: int option
}
type FilteredRecord = {
Id: int
Attr1: int
Attr2: int
Attr3: int
Attr4: int
Attr5: int
Attr6: int
}
let optionRecords = [for i in 1..5 ->
{
OptionRecord.Id = i
Attr1 = Some i
Attr2 =
match i % 2 = 0 with
| true -> Some i
| false -> None
Attr3 = Some i
Attr4 = Some i
Attr5 = Some i
Attr6 = Some i
}]
let recordFilter (x:OptionRecord) =
match x.Attr1, x.Attr2, x.Attr3, x.Attr4, x.Attr5, x.Attr6 with
| Some attr1, Some attr2, Some attr3, Some attr4, Some attr5, Some attr6 ->
Some {
FilteredRecord.Id = x.Id
Attr1 = attr1
Attr2 = attr2
Attr3 = attr3
Attr4 = attr4
Attr5 = attr5
Attr6 = attr6
}
| _, _, _, _, _, _ -> None
let filteredRecords =
optionRecords
|> List.choose recordFilter