What's the idiomatic way to express this "monadic pattern"?

I’m using vague phrasing here because I haven’t studied this subject properly yet.

I’d like to know if this add function is idiomatic F#? Or can it be expressed in a better way?

let (>>=) o f =
    match o with
    | Some x -> f x
    | None -> None

let add x y =
    x >>= fun x ->
    y >>= fun y ->
    Some (x + y)

let printRes res =
    match res with
    | None -> printfn "None"
    | Some a -> printfn "Some %O" a

// dotnet fsi monads.fsx
printf "\n--- MONADS EXAMPLE ---\n\n"
printf "add (Some 1) (Some 2)      =>   ";; printRes <| add (Some 1) (Some 2);;
printf "add (Some 1) None          =>   ";; printRes <| add (Some 1) None;;
printf "add None     (Some 2)      =>   ";; printRes <| add None (Some 2);;
printf "add None     None          =>   ";; printRes <| add None None;;



add (Some 1) (Some 2)      =>   Some 3
add (Some 1) None          =>   None
add None     (Some 2)      =>   None
add None     None          =>   None

Also, I’m confused about Option.bind. It looks like it’s got the params in the wrong order, I can’t find a way to use it effectively in its original form.

let bindRev o fn = Option.bind fn o

let mult x y =
    bindRev x (fun x ->
    bindRev y (fun y ->
    Some(x * y)))

Am I missing something?

I think an argument can be made that idiomatically, any monads in F# would be expressed with computation expressions. Though there isn’t a builtin one for option or a lot of other structures, so that might be a controversial statement. There are many implementations for an option CE, however. See f# - is there an option<> computation expression anywhere? - Stack Overflow. So using F#x for example, the add function would look like

let add x y = maybe {
  let! x' = x
  let! y' = y
  return x' + y'

as far as using Option.bind, you’re expected to use it with the pipeline operator

let mult x y = 
  x |> Option.bind (fun x ->
  y |> Option.bind (fun y -> 
  Some (x * y)))


I somehow got confused by syntax, Option.bind looks great like this. I’ll keep things simple and use that for now.

The only annoying thing is the formater which wants to either inline the function body, or indent it to the right (like an arrow).

It looks like this rule regarding lambdas is applied: F# code formatting guidelines | Microsoft Learn

Yeah, the formatting is one of the common reasons for using a computation expression or the infix >>= operator. If you haven’t already started working through it, I’d highly recommend the F# for fun and profit article series on this whole concept:

Thanks, that article was excellent!

In general, in other programming languages, I don’t like shadowing variables.

But I find rebinding with let or let! pretty handy and I can’t see any drawbacks to doing that if the types differ and the previous binding can be “thrown away”. Like this:

let minus x y =
    maybe {
        let! x = x
        let! y = y
        return x - y

Is this considered bad practice?

I can’t find any “official” advice on shadowing. I would certainly shadow in this case, I just didn’t include it in my example because it’s a separate topic from monads and could add confusion.
Someone else asked the question about shadowing earlier, and I wrote up my personal thoughts on the matter, but as I pointed out there, it’s very opinionated and I don’t have any “official” guidance to point to.

Thanks very much for that feedback @ntwilson