Search code examples
f#quotations

Cannot get the name of a function passed as a parameter with code quotations, in F#


I have a function that looks like that:

let rec retryAsync (retryAttempts: TimeSpan list) (request: unit -> Async<Result<'a, ExchangeError>>) : Async<Result<'a, ExchangeError>> = ....

and, upon an error I would like to print the name of the function passed as 'request'. It has this signature:

unit -> Async<Result<'a, ExchangeError>>

I thought about using something like this (slightly modified version of code I found online):

module DocumentGetter =
    let GetName ([<ReflectedDefinition>]x:Expr<_->_>) =
        match x with
        | DerivedPatterns.Lambdas(_, Patterns.Call(_,methodInfo,_)) ->
            methodInfo.Name
        | _ -> "unknown"

but then I get this compile error:

[FS0001] The type 'unit -> Async<Result<'a,ExchangeError>>' is not compatible with the type 'Quotations.Expr<('b -> 'c)>'

If I pass the main function (retryAsync), I can get the name out, but I can't get the name of the function passed to it. Why is that?


Solution

  • Implicit conversion to F# quotations based on the ReflectedDefinition attribute does not work for let-bound functions, but only for static members. The following works as expected:

    type DocumentGetter =
      static member GetName ([<ReflectedDefinition>]x:Expr<_->_>) =
          match x with
          | DerivedPatterns.Lambdas(_, Patterns.Call(_,methodInfo,_)) ->
              methodInfo.Name
          | _ -> "unknown"
    
    let rec retryAsync (retryAttempts: TimeSpan list) 
      (request: unit -> Async<Result<'a, ExchangeError>>) 
        : Async<Result<'a, ExchangeError>> = failwith "!"
    
    DocumentGetter.GetName retryAsync
    

    That said, I'm not quite sure what your scenario for this is. It sounds like you are trying to do something pretty complicated - I think there might be an easier way to solve your actual problem without doing this.