Static constraints on item types cannot recognize system type extensions

In my quest to improve F # and better understand how Suave.io works, I tried to create some reusable functions / statements for composing functions. I understand that Suave actually implements its>>> operator to work specifically for the async option, but I thought it would be interesting for me to try and generalize it.

The code below is inspired by too many sources for lending, and it works well for types that I define myself, but I can't get it to work for system types. Although extensions like Nullable and Option compile fine, they are not recognized as matching member restrictions in the bind function.

When I was not able to get it to work for the option, I was hoping this could be due to the fact that the option was special in F #, so I tried using Nullable, but unfortunately no cigar.

The corresponding errors and the output from fsi are 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'
+4
source share
1 answer

Why extension methods are not taken into account in the static restrictions of elements is a question that has been asked many times, and, of course, it will continue to be requested until this function is implemented in the F # compiler.

. , F # .

, , FsControl.

:

#nowarn "3186"
#r "FsControl.dll"

open FsControl.Operators

// Example with Result 
type public Result<'a,'b> = 
    | Success of 'a 
    | Error of 'b

type public Result<'a,'b> with
    static member Return v = Success v
    static member Bind (v, f) = 
        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 Option

let oF a = if a > 0 then Some a else None
// val oF : a:int -> int option

let oG a = if a < 10 then Some a else None
// val oG : a:int -> int option

let oFG = oF >=> oG
// val oFG : (int -> int option)

oFG 0
// val it : int option = None

oFG 1
// val it : int option = Some 1

Choice Success/Error Success on the top of Choice :

type Result<'a, 'b> = Choice<'a, 'b>
let  Success x :Result<'a, 'b> = Choice1Of2 x
let  Error   x :Result<'a, 'b> = Choice2Of2 x
let  (|Success|Error|) = function Choice1Of2 x -> Success x | Choice2Of2 x -> Error x

- .

, Nullable, , Nullable , , , Option .

+3

Source: https://habr.com/ru/post/1651609/


All Articles