简体   繁体   中英

How to define a zero element when using discriminated unions in F# Array functions

OK, a question, I would like to use an array of discriminated unions in the Array functions. In the code below, I define a type ResultVari that is either Unknown or a floating point value. I also define the infix plus operator for the type, which returns a value only if both args are not Unknown . This works fine.

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

Using summation2 the program works as expected with the sum for example1 being 12.6 and for example2 being Unknown .

But I don't understand why summation doesn't work - the compiler complains "this value is not a function and cannot be applied". In another attempt (not shown), I also got the error of a missing get_Zero element which I understand -- the sum function has to use some type of a zero definition to start the summation, and using the fold function with my Value(0.0) as the start value like in summation2 solves that.

So is there a way to define a get_Zero element for a discriminated union, or would I have to use a record type instead for ResultVari? Then I could use Array.sum instead of using Array.fold.

You need to add a zero element to use array.sum - like this:

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)

Then the code becomes:

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

This makes sense because when you sum something you need to start from zero and without the zero member, the compiler doesn't know where to start.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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