Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

F# inline function: instance member constraint fail

I try to use member constraint with my inline function like this:

    let inline extractMessageAsync 
        (envelope: ^env when ^env: 
            (member GetBodyAsync: unit-> Task<'a>)) =
    envelope.GetBodyAsync()

But I get the following error:

Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved.

Although I understand that compiler needs more info about this type, I don't understand why, especially since it works just fine with static member constraints for operators like (+) or (*) etc.

like image 940
kagetoki Avatar asked Aug 14 '26 20:08

kagetoki


2 Answers

You can write a shorter and more generic version like this:

let inline GetBodyAsync x = (^a: (member GetBodyAsync: unit -> ^b) x)

Now writing GetBodyAsync is the equivalent of writing fun x -> x.GetBodyAsync() regardless of the return type of the method.

Usage:

open System.Threading.Tasks
type A() =
    member this.GetBodyAsync() = Task.FromResult 1

type B() =
    member this.GetBodyAsync() = async { return 2 }

A() |> GetBodyAsync |> fun x -> x.Result // 1
B() |> GetBodyAsync |> Async.RunSynchronously // 2
like image 109
TheQuickBrownFox Avatar answered Aug 17 '26 16:08

TheQuickBrownFox


try this:

let inline extractMessageAsync<'a, ^env
         when ^env: (member GetBodyAsync: unit-> Task<'a>)>
        (envelope: ^env) =
    (^env: (member GetBodyAsync: unit-> Task<'a>) envelope)
like image 34
Szer Avatar answered Aug 17 '26 15:08

Szer