Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best way to use match..with to conditionally insert values into a sequence expression?

Tags:

f#

I thought maybe match .. with might work like if inside a sequence expression:

let foo (m: 'a option) =
    [ yield 'a'
      match m with
        | Some _ -> yield 'b'
      yield 'c' ]

That is, I only need to specify the matching case(s) while the fail case is treated as a no-op. Unfortunately this is not the case, a non-match raises an exception.

I found that I can still get the desired result if I use yield! like this:

let bar (m: 'a option) =
    [ yield 'a'
      match m with
        | Some _ -> yield 'b'
        | _ -> yield! []
      yield 'c' ]

This works but is it the best way? Just wondering if there is any more standard way of doing this.

like image 301
Strecster Avatar asked Oct 30 '22 08:10

Strecster


1 Answers

Funk's answer is correct, but you can also replace yield! [] with a simple ():

let bar (m: 'a option) =
    [ yield 'a'
      match m with
        | Some _ -> yield 'b'
        | _ -> ()
      yield 'c' ]

The rules inside computation expressions are that any expression that evaluates to the unit type (that is, the () value) will be replaced by that expression's "zero" value (whatever "zero" means for that type of thing). For a list, the "zero" value is the empty list. This is also what is happening behind the scenes when you have an if statement without an else clause: the else clause is implicitly else (). And so Funk's answer is equivalent to if Option.isSome m then yield 'b' else (), which in a list expression is equivalent to if Option.isSome m then yield 'b' else yield! [].

Hopefully that explanation is clear rather than confusing you further; computation expressions always take a bit of brain-bending before they "click" and you get it. If you need more explanation, let me know.

like image 193
rmunn Avatar answered Jan 02 '23 20:01

rmunn