Skip to content

Instantly share code, notes, and snippets.

@lucasteles
Last active November 1, 2022 23:16
Show Gist options
  • Save lucasteles/7bd4e8134bcf69b7c90cbb44b5fb2634 to your computer and use it in GitHub Desktop.
Save lucasteles/7bd4e8134bcf69b7c90cbb44b5fb2634 to your computer and use it in GitHub Desktop.
option monad on fsharp
open System
//Helpers
let printOpt opt =
match opt with
|None -> printfn "None"
|Some v -> printfn "Some %s" v
// safe functions
let exclaimIt str = if str = "" then None else Some (str + "!")
let doubleIt str = if str = "" then None else Some (str + str)
let upperIt str = if str = "" then None else Some (str |> String.map Char.ToUpper)
//normal pipe with bind
// if we use Option.map we will get a (string option option), but with bind we get flated result (string option)
let pipeOpt = Some "a"
|> Option.bind exclaimIt
|> Option.bind doubleIt
|> Option.bind upperIt
printOpt pipeOpt //Some A!A!
//is very annoying repeat this pattern everywhere
//lets create a Haskell inspired bind operator
let (>>=) a b =
match a with
| None -> None
| Some x -> x |> b
//so
let operatorOpt =
Some "a"
>>= exclaimIt
>>= doubleIt
>>= upperIt
printOpt operatorOpt //Some A!A!
//but...
//we have a nested bind problem if needed
let chainOpt =
"a" |> (fun v ->
exclaimIt v >>= (fun x ->
doubleIt x >>= (fun y ->
upperIt y >>= (fun z ->
Some (x + y + z) )))) //return
printOpt chainOpt //Some a!a!a!A!A!
//awfull!
//lets create a computed expression definition for option
type MaybeBuilder() =
member this.Bind(x, f) =
match x with
| None -> None
| Some a -> f a
member this.Return(x) =
Some x
let maybe = new MaybeBuilder()
// then
let computed =
maybe {
let! x = exclaimIt "a"
let! y = doubleIt x
let! z = upperIt y
return x + y + z
}
printOpt computed //Some a!a!a!A!A!
//that's all...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment