I'm having this method which takes a Expr as parameter:
member x.HasSeq (expr:Expr<'a -> 'b seq>) =
let casted = <# fun z -> (%expr) z :?> ICollection<'b> #>
ManyNavPropertyInfo(cfg.HasMany <| toLinq casted)
What I want is to cast the 'b seq to an ICollection<'b>, which seems to work as it should, however when it reaches the line where it's going to convert the Expr to LINQ (need to do this since cfg.HasMany excepts a System.Expression<Func<'a,ICollection<'b>>>) it simply throws an exception saying:
InvalidOperationException:
The expression 'z =>
UnboxGeneric(ToFSharpFunc(z =>
z.Books).Invoke(z))' is not a valid
property expression. The expression
should represent a property: C#: 't =>
t.MyProperty' VB.Net: 'Function(t)
t.MyProperty'.
The function I use for converting Expr to LINQ:
let toLinq (exp : Expr<'a -> 'b>) =
let linq = exp.ToLinqExpression()
let call = linq :?> MethodCallExpression
let lambda = call.Arguments.[0] :?> LambdaExpression
Expression.Lambda<Func<'a, 'b>>(lambda.Body, lambda.Parameters)
I've used the toLinq function before without problems - I think it's because I cast b seq to ICollection<'b> which leaves UnboxGeneric in the Expr and when passing the Expr to toLinq it simply dosent know what to do with the UnboxGeneric - but of course thats just a theory, and I dont know what to do at all, in order to resolve it.
Your reasoning is correct - the problem is that the HasMany method recognizes only specific C# expression trees and the expression tree that your F# code generates is different.
My guess is that EF only handles a case when the expression tree is a plain access to a property of the right type - in the C# syntax something like: x => x.Foo (without any casting etc.). I think that the best option would be to modify your code to also expect a function 'a -> ICollection<'b>.
If you have some way for building a correct expression tree - e.g. if user specifies x => x.Foo, you want to return x => x.FooInternal, then you can use patterns & functions for working with F# quotations to rebuild the expression tree:
let hasSeq (e:Expr<'a -> seq<'b>>) =
match e with
| Patterns.Lambda(v, Patterns.PropertyGet(Some instance, propInfo, [])) ->
printfn "Get property %s of %A" propInfo.Name instance
// TODO: Use 'Expr.Lambda' & 'Expr.PropGet' to construct
// an expression tree in the expected format
| _ -> failwith "Not a lambda!"
... but keep in mind that the result needs to match the structure expected by HasMany. I guess that replacing the actual property specified by the user with some other property (e.g. some internal version that has the right type) is pretty much the only thing you can do.
Related
I am trying to develop F# type provider.
It provides some DTOs (with the structure described in some external document) and a set of methods for processing them. The processing algorithm is based on reflection, and I want to have a single quotation representing it.
Generally, this algorithm must pass all method call arguments to the already written function serialize: obj -> MySerializationFormat, storing all results in a list, so I getting a value of MySerializationFormat list.
Code sample below shows, how I tried to do that for first time:
let serialize (value: obj) = ...
let processingCode: Expr list -> Expr =
fun args ->
let serializeArgExpr (arg: Expr) = <# serialize %%arg} #>
let argsExprs = List.map serializeArgExpr args
let serializedArgList =
List.foldBack (fun head tail -> <# (%head) :: (%tail)#>) argsExprs <# [] #>
// futher processing
At that point I faced with exception: In function serializeArgExpr the actual type of value in arg: Expr may vary, it can be some primitive type (e.g string, int, float), or some provided type. The problem is %% operator treats that arg as an expression of the obj type. Type check is performed on that line in Microsoft.FSharp.Quotations.Patterns module, in function fillHolesInRawExpr.
So, as the actual type of my term not matched the treated type for "hole" in the quotation, it throws invalidArg.
I have tried several technics to avoid these exceptions with casting operations in my quotation, but they don't work. Then I found Expr.Coerce(source, target) function, which looks like solving my problem. I have changed the code of serializeArgExpr to something like that:
let serializeArgExpr (arg: Expr) =
let value' = Expr.Coerce(value, typeof<obj>)
<# serialize %%value' } #>
Then faced a new strange exception:
The design-time type (point to a code line that uses my processingCode) utilized by a type provider was not found in the target reference assembly set
For me, it seems that my problem is to cast the type of value in any input Expr to an obj type. Thank you for diving in and trying to help.
I am trying to write a typed abstract syntax tree datatype that can represent
function application.
So far I have
type Expr<'a> =
| Constant of 'a
| Application of Expr<'b -> 'a> * Expr<'b> // error: The type parameter 'b' is not defined
I don't think there is a way in F# to write something like 'for all b' on that last line - am I approaching this problem wrongly?
In general, the F# type system is not expressive enough to (directly) define a typed abstract syntax tree as the one in your example. This can be done using generalized algebraic data types (GADTs) which are not supported in F# (although they are available in Haskell and OCaml). It would be nice to have this in F#, but I think it makes the language a bit more complex.
Technically speaking, the compiler is complaining because the type variable 'b is not defined. But of course, if you define it, then you get type Expr<'a, 'b> which has a different meaning.
If you wanted to express this in F#, you'd have to use a workaround based on interfaces (an interface can have generic method, which give you a way to express constraint like exists 'b which you need here). This will probably get very ugly very soon, so I do not think it is a good approach, but it would look something like this:
// Represents an application that returns 'a but consists
// of an argument 'b and a function 'b -> 'a
type IApplication<'a> =
abstract Appl<'b> : Expr<'b -> 'a> * Expr<'b> -> unit
and Expr<'a> =
// Constant just stores a value...
| Constant of 'a
// An application is something that we can call with an
// implementation (handler). The function then calls the
// 'Appl' method of the handler we provide. As this method
// is generic, it will be called with an appropriate type
// argument 'b that represents the type of the argument.
| Application of (IApplication<'a> -> unit)
To represent an expression tree of (fun (n:int) -> string n) 42, you could write something like:
let expr =
Application(fun appl ->
appl.Appl(Constant(fun (n:int) -> string n),
Constant(42)))
A function to evaluate the expression can be written like this:
let rec eval<'T> : Expr<'T> -> 'T = function
| Constant(v) -> v // Just return the constant
| Application(f) ->
// We use a bit of dirty mutable state (to keep types simpler for now)
let res = ref None
// Call the function with a 'handler' that evaluates function application
f { new IApplication<'T> with
member x.Appl<'A>(efunc : Expr<'A -> 'T>, earg : Expr<'A>) =
// Here we get function 'efunc' and argument 'earg'
// The type 'A is the type of the argument (which can be
// anything, depending on the created AST)
let f = eval<'A -> 'T> efunc
let a = eval<'A> earg
res := Some <| (f a) }
res.Value.Value
As I said, this is a bit really extreme workaround, so I do not think it is a good idea to actually use it. I suppose the F# way of doing this would be to use untyped Expr type. Can you write a bit more about the overall goal of your project (perhaps there is another good approach)?
I'm trying to use AutoMapper from F#, but I'm having trouble setting it up due to AutoMapper's heavy use of LINQ Expressions.
Specifically, the AutoMapper type IMappingExpression<'source, 'dest> has a method with this signature:
ForMember(destMember: Expression<Func<'dest, obj>>, memberOpts: Action<IMemberConfigurationExpression<'source>>)
This is typically used in C# like this:
Mapper.CreateMap<Post, PostsViewModel.PostSummary>()
.ForMember(x => x.Slug, o => o.MapFrom(m => SlugConverter.TitleToSlug(m.Title)))
.ForMember(x => x.Author, o => o.Ignore())
.ForMember(x => x.PublishedAt, o => o.MapFrom(m => m.PublishAt));
I made an F# wrapper that arranges things so that type inference can work. This wrapper allows me to translate the C# example above into something like this:
Mapper.CreateMap<Post, Posts.PostSummary>()
|> mapMember <# fun x -> x.Slug #> <# fun m -> SlugConverter.TitleToSlug(m.Title) #>
|> ignoreMember <# fun x -> x.Author #>
|> mapMember <# fun x -> x.PublishedAt #> <# fun m -> m.PublishAt #>
|> ignore
This code compiles, and it seems pretty clean as far as syntax and usage. However, at runtime AutoMapper tells me this:
AutoMapper.AutoMapperConfigurationException: Custom configuration for members is only supported for top-level individual members on a type.
I presume this is caused by the fact that I have to convert Expr<'a -> 'b> into Expression<Func<'a, obj>>. I convert the 'b to obj with a cast, which means my lambda expression is no longer simply a property access. I get the same error if I box the property value in the original quotation, and don't do any splicing at all inside forMember (see below). However, if I don't box the property value, I end up with Expression<Func<'a, 'b>> which does not match the parameter type that ForMember expects, Expression<Func<'a, obj>>.
I think that this would work if AutoMapper's ForMember was completely generic, but forcing the return type of the member access expression to be obj means that I can only use it in F# for properties that are already directly of type obj and not a subclass. I can always resort to using the overload of ForMember that takes the member name as a string, but I thought I'd check to see if anyone has a brilliant work-around before I give up on compile-time typo-checking.
I'm using this code (plus the LINQ part of F# PowerPack) to convert an F# quotation into a LINQ expression:
namespace Microsoft.FSharp.Quotations
module Expr =
open System
open System.Linq.Expressions
open Microsoft.FSharp.Linq.QuotationEvaluation
// http://stackoverflow.com/questions/10647198/how-to-convert-expra-b-to-expressionfunca-obj
let ToFuncExpression (expr:Expr<'a -> 'b>) =
let call = expr.ToLinqExpression() :?> MethodCallExpression
let lambda = call.Arguments.[0] :?> LambdaExpression
Expression.Lambda<Func<'a, 'b>>(lambda.Body, lambda.Parameters)
This is the actual F# wrapper for AutoMapper:
namespace AutoMapper
/// Functions for working with AutoMapper using F# quotations,
/// in a manner that is compatible with F# type-inference.
module AutoMap =
open System
open Microsoft.FSharp.Quotations
let forMember (destMember: Expr<'dest -> 'mbr>) (memberOpts: IMemberConfigurationExpression<'source> -> unit) (map: IMappingExpression<'source, 'dest>) =
map.ForMember(Expr.ToFuncExpression <# fun dest -> ((%destMember) dest) :> obj #>, memberOpts)
let mapMember destMember (sourceMap:Expr<'source -> 'mapped>) =
forMember destMember (fun o -> o.MapFrom(Expr.ToFuncExpression sourceMap))
let ignoreMember destMember =
forMember destMember (fun o -> o.Ignore())
Update:
I was able to use Tomas's sample code to write this function, which produces an expression that AutoMapper is satisfied with for the first argument to IMappingExpression.ForMember.
let toAutoMapperGet (expr:Expr<'a -> 'b>) =
match expr with
| Patterns.Lambda(v, body) ->
// Build LINQ style lambda expression
let bodyExpr = Expression.Convert(translateSimpleExpr body, typeof<obj>)
let paramExpr = Expression.Parameter(v.Type, v.Name)
Expression.Lambda<Func<'a, obj>>(bodyExpr, paramExpr)
| _ -> failwith "not supported"
I still need the PowerPack LINQ support to implement my mapMember function, but they both work now.
If anyone is interested, they can find the full code here.
Now that F# is happy to generate a Expression<Func<...>> directly from a fun expression, this is relatively easy to solve. The biggest problem now is that the F# compiler seems to get confused by the overloading of the ForMember method, and is unable to infer correctly what you want. This can be circumvented by defining an extension method with a different name:
type AutoMapper.IMappingExpression<'TSource, 'TDestination> with
// The overloads in AutoMapper's ForMember method seem to confuse
// F#'s type inference, forcing you to supply explicit type annotations
// for pretty much everything to get it to compile. By simply supplying
// a different name,
member this.ForMemberFs<'TMember>
(destGetter:Expression<Func<'TDestination, 'TMember>>,
sourceGetter:Action<IMemberConfigurationExpression<'TSource, 'TDestination, 'TMember>>) =
this.ForMember(destGetter, sourceGetter)
You can then use the ForMemberFs method more or less as the original ForMember is intended to work, e.g.:
this.CreateMap<Post, Posts.PostSummary>()
.ForMemberFs
((fun d -> d.Slug),
(fun opts -> opts.MapFrom(fun m -> SlugConverter.TitleToSlug(m.Title)))
I'm not quite sure how to fix the generated expression tree (that's doable by post-processing it, but it is pain to find out what AutoMapper expects). However, there are two alternatives:
As a first option - the expressions that you need to translate are fairly simple. They are mostly just method calls, property getters and uses of a variable. This means that it should be possible to write your own quotation to expression trees translator that produces exactly the code you want (then you can also add your own handling of obj, perhaps by calling Expression.Convert to build the expression tree). I wrote a simple quotation tranlsator as a sample, which should handle most of the stuff in your sample.
As a second option - if AutoMapper provides an option to specify just a property name - you could just use quotations of the form <# x.FooBar #>. These should be quite easy to deconstruct using the Patterns.PropertyGet pattern. The API should maybe look like this:
Mapper.CreateMap<Post, Posts.PostSummary>(fun post summary mapper ->
mapper |> mapMember <# post.Slug #> // not sure what the second argument should be?
|> ignoreMember <# post.Author #> )
Or, in fact, you could use this style of API even in the first case, because you don't need to write lambda expressions repeatedly for every single mapping, so maybe it is a bit nicer :-)
Alright... this question is more or less related to one I've asked earlier today (F# - "Not a valid property expression"), which #Tomas Petricek answer perfectly - however it seems my lack of knowledge and the DLR, requires me to ask once again (been trying for quite a while to mix something up without luck at all).
I'm having this function (stolen from the example Tomas gave in the previous thread):
let hasSeq (e:Expr<'a -> seq<'b>>) =
match e with
| Patterns.Lambda(v, Patterns.PropertyGet(Some instance, propInfo, [])) ->
printfn "Get property %s of %A" propInfo.Name instance
// TODO: Use 'Expr.Lambda' & 'Expr.PropGet' to construct
// an expression tree in the expected format
| _ -> failwith "Not a lambda!"
How would I reconstruct the expression tree with Expr.Lambda and Expr.PropGet? - I need to make the seq<'b> to ICollection<'b> instead, so that the expression in the end is like: 'a -> ICollection<'b>
Well, if you've already decomposed quotation, then maybe you can create required expression tree by yourself without ToLinqExpression from PowerPack?
type A =
member this.Values : int[] = failwith ""
open Microsoft.FSharp.Quotations
type F<'T, 'R> = System.Func<'T, 'R>
type E = System.Linq.Expressions.Expression
type IC<'T> = System.Collections.Generic.ICollection<'T>
let toLinqPropGet (e : Expr<'T -> #seq<'R>>) =
match e with
| Patterns.Lambda(_, Patterns.PropertyGet(Some _, pi, []))
when typeof<IC<'R>>.IsAssignableFrom(pi.PropertyType) ->
let p = E.Parameter(typeof<'T>)
let propGet = E.Property(p :> E, pi)
E.Lambda<F<'T, IC<'R>>>(propGet, p) :> E
| _ -> failwith "PropGet expected"
let r = toLinqPropGet <# fun (x : A) -> x.Values #>
printfn "%A" r
This isn't going to work.
You want to build a quotation of type Entity -> ICollection<Something> and you have a quotation of type Entity -> seq<Something>. However, entity framework only supports simple lambda functions that get some property (e.g. x => x.SomeProperty).
If your Entity has only a property Foo of type seq<Something>, then there is no way you could build a quotation with the required structure (lambda that just gets a property) and of the required type (Entity -> ICollection<Something>), because the type of the property doesn't match!
What I suggested earlier is to change the entity to also have a property FooInternal of the right type (ICollection<Something>). Then you could build a quotation x => x.FooInternal, which would work fine with entity framework.
Perhaps you could give more details about what you're actually trying to achieve? We can try to help with technical details, but it seems that you may need to adjust your design a bit (to actually work with the ICollection type as required by EF).
My questions will no end take...
I've the function:
let hasMany (expr:Expr<'a -> seq<'b>>)
now I want to extract the seq<'b> from the Expr since I need to cast it to an ICollection<'b> and wrap it back into a new Expr - Why not just make it take an Expr that takes an ICollection<'b> in the first place you may ask - simple enough the user would need to first cast the seq<'b> to an ICollection<'b>, which I'm trying to avoid since I'm creating a library thats going to be used by others than me, and I want it to be easy and clean.
Short: How do I extract the seq<'b>from the Expr?
Your question doesn't make sense to me. Given your types, there is no seq<'b> in expr - expr is an expression wrapping a function which returns a seq<'b>. For instance, with the signature you've got, it would be valid to call
hasMany <# id #>
since id can be given the type 'b seq -> 'b seq. However, clearly <# id #> doesn't contain a seq<'b>!
If what you're asking is to convert your Expr<'a -> seq<'b>> into an Expr<'a -> ICollection<'b>>, then try this:
let hasMany (expr : Expr<'a -> 'b seq>) =
<# fun x -> (%expr) x :?> ICollection<'b> #>