Reputation: 1367
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?
Upvotes: 6
Views: 363
Reputation: 243051
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)
Upvotes: 8