Viktor Jeppesen
Viktor Jeppesen

Reputation: 125

how to properly use Result.bind

I am currently trying to implement some validation in my F# program but i'm facing som compile time errors, which I can't solve. Boiled down, i'm trying to do this

let ifFalseThenError x errorMessage = function 
   | true -> Ok x 
   | false -> Error errorMessage
let val1 (initialeSandssynligheder : float[]) =
       initialeSandssynligheder
       |> Seq.sum
       |> (fun x -> x < 2)
       |> (fun x -> ifFalseThenError initialeSandssynligheder "Some error")

let val2 initialeSandssynligheder = 
    initialeSandssynligheder 
    |> Array.exists ((<) 0.0) 
    |> (fun x -> ifFalseThenError initialeSandssynligheder "SomeOtherError")

let beregnAlleOvergangssandsynligheder (initialeSandssynligheder: float[])  : float[] = 
       let initialeSandssynligheder = [|1.0;1.0;1.0;1.0;1.0|] 
       let initssh = initialeSandssynligheder 
                     |> val1
                     |> Result.bind val2  // Error here
       initssh

So this my compiler tells me, that I have a type mismatch. I understand, that both val1 and val2 takes a float[] and returns a Result<Float[], String> and I need to compensate for that, when im piping in my val2 and I though I could do that by using Result.bind. What am i misundertanding.

My error:

Error   FS0001  Type mismatch. Expecting a
    '(bool -> Result<float [],string>) -> 'a'    
but given a
    'Result<'b,'c> -> Result<'d,'c>'    
The type 'bool -> Result<float [],string>' does not match the type 'Result<'a,'b>'... (Path)

So the message is telling my what I though I was compensating for, when adding the Result.bind statement to the last validation

Upvotes: 2

Views: 764

Answers (2)

Koenig Lear
Koenig Lear

Reputation: 2436

Your intuition on how to use Result.bind is correct. However, there are a number of errors in your code:

  1. The function ifFalseThenError takes a boolean which you're not passing by, in both val1, val2.

  2. In val1 you need to use a float value, e.g. 2.0 rather than int 2.

Here it's corrected

let ifFalseThenError x errorMessage = function 
   | true -> Ok x 
   | false -> Error errorMessage
let val1 (initialeSandssynligheder : float[]) =
       initialeSandssynligheder
       |> Seq.sum
       |> (fun x -> x < 2.0)
       |> (fun x -> ifFalseThenError initialeSandssynligheder "Some error" x)

let val2 initialeSandssynligheder = 
    initialeSandssynligheder 
    |> Array.exists ((<) 0.0) 
    |> (fun x -> ifFalseThenError initialeSandssynligheder "SomeOtherError" x)

let beregnAlleOvergangssandsynligheder (initialeSandssynligheder: float[])  = 
       let initialeSandssynligheder = [|1.0;1.0;1.0;1.0;1.0|] 


       let initssh = initialeSandssynligheder 
                     |> val1 
                     |> Result.bind val2
       initssh

ps. A good way to solve these problems is to add type annotations to all of your functions and parameters.

Upvotes: 1

Andreas &#197;gren
Andreas &#197;gren

Reputation: 3929

As stated in comments there are multiple compilation errors:

  1. Incorrect numeric data type
  2. Missing arguments to function
  3. Wrong return type hint in beregnAlleOvergangssandsynligheder

Here's a version that resolves these compilation errors with comments describing where changes were made:

let ifFalseThenError x errorMessage =
  function
  | true -> Ok x
  | false -> Error errorMessage

let val1 (initialeSandssynligheder: float array) =
  initialeSandssynligheder
  |> Seq.sum
  |> (fun x -> x < 2.0) // changed to float
  |> (fun x -> ifFalseThenError initialeSandssynligheder "Some error" x) // include x arg

let val2 initialeSandssynligheder =
  initialeSandssynligheder
  |> Array.exists ((<) 0.0)
  |> (fun x -> ifFalseThenError initialeSandssynligheder "SomeOtherError" x) // include x arg

let beregnAlleOvergangssandsynligheder (initialeSandssynligheder: float array) : Result<float array, string> = // Mixing list/array, hint return result
  let initssh =
    initialeSandssynligheder
    |> val1
    |> Result.bind val2 // Error here

  initssh

beregnAlleOvergangssandsynligheder [| 1.0; 1.0; 1.0; 1.0; 1.0 |] // Error because sum > 2
beregnAlleOvergangssandsynligheder [| -1.0 |] // Error because of negative value
beregnAlleOvergangssandsynligheder [| 1.0 |] // Ok

I would also look over the usages of array/list/seq, e.g. you are using array's but I'm not seeing any specific need for that here, maybe seq would be enough? Try to settle on the one you need.

Upvotes: 3

Related Questions