Как определить нулевой элемент при использовании размеченных объединений в функциях массива F#

Хорошо, вопрос, я хотел бы использовать массив размеченных объединений в функциях массива. В приведенном ниже коде я определяю тип ResultVari, который является либо Unknown, либо значением с плавающей запятой. Я также определяю оператор infix plus для типа, который возвращает значение, только если оба аргумента не равны Unknown. Это прекрасно работает.

type ResultVari =
    | Unknown
    | Value of float
    static member (+) (a,b) =   // add two ResultVari's together
        match a,b with
        | Value(av),Value(bv) -> Value(av + bv)  // only has a value if both args do.
        | _ -> Unknown

(* Summation of array of ResultVari, such that if any are unknown then the result is Unknown *)
let example1 = [| Value(4.0); Value(5.5); Value(3.1) |]     // summation should be 12.6
let example2 = [| Value(4.0); Unknown; Value(3.1) |]        // summation should be Unknown

let summation (varArray:ResultVari array) =
    Array.sum (+) varArray       //ERROR this value is not a function and cannot be applied

let summation2 (varArray:ResultVari array) =
    Array.fold (+) (Value(0.0)) varArray       // Works

let sum_example1 = summation2 example1
let sum_example2 = summation2 example2

printfn "%A" sum_example1  // 12.6
printfn "%A" sum_example2  // Unknown

При использовании summation2 программа работает, как и ожидалось, с суммой для example1, равной 12,6, и для example2, равной Unknown.

Но я не понимаю, почему summation не работает - компилятор ругается "это значение не является функцией и не может быть применено". В другой попытке (не показанной) я также получил ошибку отсутствующего элемента get_Zero, как я понимаю, функция суммирования должна использовать какой-то тип нулевого определения, чтобы начать суммирование, и использовать функцию fold с моим значением (0,0 ), так как начальное значение, как в summation2, решает это.

Итак, есть ли способ определить элемент get_Zero для размеченного объединения, или вместо этого мне придется использовать тип записи для ResultVari? Тогда я мог бы использовать Array.sum вместо Array.fold.


person user1857742    schedule 01.05.2016    source источник
comment
Разве вы не заново изобретаете типы option только с этим типом ResultVari?   -  person Mark Seemann    schedule 01.05.2016
comment
Не совсем так, я хотел бы отличать неустановленную переменную от других. Но вы правы, возможно, вариант «Нет» мог бы заменить члена моего профсоюза Unset. Что касается рекомендуемой практики F#, какой выбор (мой или ваш) будет каноническим?   -  person user1857742    schedule 02.05.2016
comment
Я хотел бы отличить неустановленную переменную от других Разве это не то, что подразумевает случай None?   -  person Mark Seemann    schedule 02.05.2016
comment
@MarkSeemann Я думаю, что значение None может использоваться для обозначения того, что переменная не установлена, но разве концепция None не означает, что элемент «отсутствует» или что-то вроде нуля? Хотя в этом параметре (возможно, неясном) он предназначен для представления переменной, которая может быть установлена ​​или не установлена, например, в ходе исследования ветвей и границ или около того. Так что в этом случае мой выбор использования Unset был бы более подходящим, чем использование этого типа опции и использование None для обозначения того, что это значение еще не установлено (что, я согласен, может работать).   -  person user1857742    schedule 03.05.2016


Ответы (1)


Вам нужно добавить элемент zero для использования array.sum - вот так:

type ResultVari =
    | Unknown
    | Value of float
    static member (+) (a,b) =   // add two ResultVari's together
        match a,b with
        | Value(av),Value(bv) -> Value(av + bv)  // only has a value if both args do.
        | _ -> Unknown
    static member Zero with get() = Value(0.0)

Тогда код становится:

let summation (varArray:ResultVari array) =
    Array.sum varArray

Это имеет смысл, потому что когда вы суммируете что-то, вам нужно начать с нуля, а без нулевого члена компилятор не знает, с чего начать.

person John Palmer    schedule 01.05.2016
comment
Спасибо. Я знал, что идея заключалась в том, что нужно определить нулевой элемент, но я не знал, как это сделать. Я думал, что его нужно определить за пределами области действия типа, как перегрузку статического оператора С++, а не как член типа. Хотя я думаю, что только что определил оператор (+) в типе, поэтому я должен был подумать о том, чтобы сделать то же самое со значением элемента. - person user1857742; 02.05.2016