3

I have a function (let's call it 'doSomething') that returns:

('a * 'b) option

and would like to achieve something like this:

let testA = doSomething ....
if testA.IsSome then return testA.Value
let testB = doSomething ....
if testB.IsSome then return testB.Value
let testC = doSomething ....
if testC.IsSome then return testC.Value

I'm looking for a computation expression, or an equivalent simple syntax, that would keep executing while the results are None, but leave on the first Some result.

Obviously I want to avoid the while if / elif / elif / ... / elif / else pyramid of doom.

Thomas
  • 10,933
  • 14
  • 65
  • 136

2 Answers2

5

One option (hehhehe) is to chain together some calls from the Option module like so:

let doSomething doThisOne tup = if doThisOne then Some tup else None

let f () =
    doSomething false (1, 2)
    |> Option.orElseWith (fun () -> doSomething false (2, 3))
    |> Option.orElseWith (fun () -> doSomething true (3, 4))
    |> Option.defaultValue (0, 0)

f () // Evaluates to (3, 4)

You might be able to use FsToolkit.ErrorHandling and applicative syntax for the option CE, but I don't know what a good way to combine results would look like, so I would personally just chain calls like above.

Phillip Carter
  • 4,895
  • 16
  • 26
3

I see it as an idiomatic pipeline:

[
  "test01";
  "test02";
  ...
]
(* |> Seq.ofList - unnecessary, as noted in the comments *)
|> Seq.tryPick doSomething (* sequentially calls 'doSomething' with test params and returns the first result of 'Some(x)' *)
Eugene Fotin
  • 1,070
  • 13
  • 24