Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert F# func to Expression<Func<..,..>>

I have a module with a function with the following signature:

module Something =
    let someFunc func = // ('TType -> 'TField) -> 'TValue
        ...

and inside that function I invoke a function from some external library which has a method with following signature (C#):

class SomeClass
{
    public ReturnType<TType> SomeMethod<TField>(func: Expression<Func<TType, TField>>) { ... }
}

When I try to pass a 'TType -> 'TField function there I get an error that it isn't convertible to Expression<Func<'TType, 'TField>>. I found the following question on StackOverflow: question

But it doesn't resolve my issue (The First answer didn't work, the second one works, but I have to change the signature of my function).

With the second answer I have to change the signature of my function to the following:

module Something =
    let someFunc func = // Expression<Func<'TType, 'TField>>) -> 'TValue
        ...

Add additional class visible for a "client" of my module, which looks like this:

type ExpressionHelper() =
    static member AsExpression<'TType, 'TField>(e: Expression<Func<'TType, 'TField>>) = e

So the final invocation instead looking like this:

let _ = Something.someFunc (fun (o: SomeType) -> o.someField)

looks like that:

let _ = Something.someFunc (ExpressionHelper.AsExpression (fun (o: SomeType) -> o.SomeField))

I don't wanna force the user of my module to convert F# function to Expression<Func<'TType, 'TField>> explicitly. I wanna do that inside my module, is there some way to achieve that?

like image 459
MNie Avatar asked Mar 21 '20 10:03

MNie


People also ask

How do we convert F?

F° to C°: Fahrenheit to Celsius Conversion Formula To convert temperatures in degrees Fahrenheit to Celsius, subtract 32 and multiply by . 5556 (or 5/9).

How do you convert F to C easy?

In other words, if you'd like to convert a temperature reading in Fahrenheit to Celsius: Start with the temperature in Fahrenheit (e.g., 100 degrees). Subtract 32 from this figure (e.g., 100 - 32 = 68). Divide your answer by 1.8 (e.g., 68 / 1.8 = 37.78)

What temp is F in Celsius?

1 Fahrenheit is equal to -17.22222222 Celsius.

How do you convert Fernites to Celsius?

The Fahrenheit to Celsius formula represents the conversion of degree Fahrenheit to degree Celsius. The formula for Fahrenheit to Celsius is °C = [(°F-32)×5]/9.


1 Answers

If you have a value of type 'T1 -> 'T2, there is no way you can turn it into a value of type Expression<Func<'T1, 'T2>>. This is not possible, because the former is a compiled function (a delegate referring to some object and its method), while the latter is a representation of the original source code.

So, you will need to use Expression<...> as the type of the argument to make this work (or Expr, which is the F# equivalent if you were to use quotations).

However, there are cases in F# where the compiler automatically turns a value created using the lambda function syntax fun x -> .. to a value of type Expression<...>. It does not do this for arguments of let-bound functions, but it does do this for the arguments of static methods. This means that you can use:

open System
open System.Linq.Expressions

type A = 
  static member foo (f:Expression<Func<int, int>>) = 
    f.ToString()

A.foo (fun n -> n + 1)
like image 150
Tomas Petricek Avatar answered Oct 06 '22 05:10

Tomas Petricek