On my quest to get better at F# and gain a better understanding on how Suave.io works, I've been attempting to create some reusable functions/operators for composing functions. I understand that Suave actually implements its >=> operator to work specifically for async option, but I thought I would be fun to try and generalize it.
The code below is inspired by too many sources to credit, and it works well for types I define myself, but I can't make it work for system types. Even though the type augmentations of Nullable and Option compiles fine, they aren't recognized as matching the member constraint in the bind function.
When I failed to make it work for Option, I had hoped that it might be due to Option being special in F#, which is why I tried with Nullable, but sadly, no cigar.
The relevant errors and output from fsi is in the code below in the comment.
Any help would be appreciated.
Thanks, John
open System
let inline bind (f : ^f) (v : ^v) =
(^v : (static member doBind : ^f * ^v -> ^r )(f, v))
// I'd prefer not having to use a tuple in doBind, but I've
// been unable to make multi arg member constraint work
let inline (>=>) f g = f >> (bind g)
// Example with Result
type public Result<'a,'b> =
| Success of 'a
| Error of 'b
type public Result<'a,'b> with
static member inline public doBind (f, v) =
match v with
| Success s -> f s
| Error e -> Error e
let rF a = if a > 0 then Success a else Error "less than 0"
let rG a = if a < 10 then Success a else Error "greater than 9"
let rFG = rF >=> rG
// val rFG : (int -> Result<int,string>)
//> rFG 0;;
//val it : Result<int,string> = Error "less than 0"
//> rFG 1;;
//val it : Result<int,string> = Success 1
//> rFG 10;;
//val it : Result<int,string> = Error "greater than 9"
//> rFG 9;;
//val it : Result<int,string> = Success 9
// So it works as expected for Result
// Example with Nullable
type Nullable<'T when 'T: (new : unit -> 'T) and 'T: struct and 'T:> ValueType> with
static member inline public doBind (f, v: Nullable<'T>) =
if v.HasValue then f v.Value else Nullable()
let nF a = if a > 0 then Nullable a else Nullable()
let nG a = if a < 10 then Nullable a else Nullable()
let nFG = nF >=> nG
// error FS0001: The type 'Nullable<int>' does not support the operator 'doBind'
type Core.Option<'T> with
static member inline doBind (f, v) =
match v with
| Some s -> f s
| None -> None
let oF a = if a > 0 then Some a else None
let oG a = if a < 10 then Some a else None
let oFG = oF >=> oG
// error FS0001: The type 'int option' does not support the operator 'doBind'