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).
Related
If the answer to this is "you are going about it all wrong", by all means let me know a more proper way. I had code which was structured like this:
type Res<'T> =
| E of (DC -> 'T)
| V of 'T
Now this type was primarily used directly, with a lot of inline code that did manual per-case binding, which is a lot of boilerplate I am trying to get rid of, so I figured I turn it into a computation expression. It wasn't too hard to get map, bind and apply right.
State was carried along through DC but this was cumbersome to get right, so I changed it to the following, which is a common signature I see in discussions with the state monad.
type Res<'T> =
| E of (DC -> DC * 'T)
| V of 'T
Then I decided to take it to the next level and introduce the Delayed monad (or Eventually or whatever its name is). So I changed my type as follows, making it recursive:
type Res<'T> =
| E of (DC -> DC * Res<'T>)
| V of 'T
I tried some variants of the following, but keep getting:
The resulting type would be infinite when unifying ''a' and 'Res<'a> -> Res<'b>'
(usually happens when I do not invoke the return, i.e. the Res.E <| below)
Or I can't seem to get my types right, the following (understandably) throws a type error, but I'm having a blind spot fixing it:
This expression was expected to have type 'Res<'a>' but here has type 'DC * Res<'a>'.
let rec bind k res =
match res with
| Res.V v -> k v // not delayed, should it be?
| Res.E e ->
Res.E <| fun dc -> bind k (e dc) // here's my error, on 'e dc'
//(fun dc -> dc, bind f (e dc))
bind k res
I understand that the signature should be ('a -> Res<'b>) -> Res<'a> -> XRes<'b>. The problem comes from getting the recursion right, at least in my head. I'm not even sure why I am feeding the result to Res.E, as in my understanding, the k continuation should already return this type anyway.
Also, I currently have the return as follows (following Steve Horsfield):
let result v = Res.V v
But also noticed in some posts (notably the hilarious Frankenfunctor) this:
let result v = Res.E <| fun dc -> dc, Res.V v
Maybe I am following a pattern I shouldn't have, but it seemed a good idea at the time, especially in trying to refactor zillions of boilerplate code and replace it with computation expressions, but perhaps I should stick to the direct evaluation, it fit in my head ;).
But I feel like I'm close... Any ideas?
I'm not quite sure what the meaning of this monad would be, but
Ok, after thinking about it a bit and reading the question's header :- ), I do understand what it means, and I can see how to build bind for it.
Your mistake is that the function wrapped in Res.E should return a tuple, but you're having it return just Res<'b> by recursively calling bind. And to mirror that, you're passing the result of e to recursive bind call in place of Res<'b> parameter, while e actually returns a tuple.
To do this correctly, you need to destructure the result of e, then pass second part to recursive bind call, and pair its result with the first part:
let rec bind (k: 'a -> 'b Res) (res: 'a Res) : 'b Res =
match res with
| V a -> k a
| E e ->
E <| fun dc ->
let dc', res' = e dc
dc', bind k res'
The terminal case, I don't believe should be also delayed. That is, I don't see a reason for it. As far as I understand, the interpretation of the V x case should be "a computation that doesn't change state and returns x", in which case making it delayed doesn't add anything but an extra lambda-expression.
I'm currently extracting information about method from type here is the relevant part of my current code (which works correctly) :
let ctorFlags = BindingFlags.NonPublic ||| BindingFlags.Public ||| BindingFlags.Instance ||| BindingFlags.Static
let methodFlags = BindingFlags.DeclaredOnly ||| ctorFlags
[
for t in Assembly.GetExecutingAssembly().GetTypes() do
for c in t.GetConstructors ctorFlags -> c :> MethodBase
for m in t.GetMethods methodFlags -> m :> MethodBase
]
|> printfn "%A"
Then I wanted to make a small change using the fact that the syntax is for pattern in expr. and that type test pattern match if given input is a match to (or a derived type of) given type ; so I wrote this :
// same flags as before
[
for t in Assembly.GetExecutingAssembly().GetTypes() do
for :? MethodBase as m in t.GetConstructors ctorFlags -> m
for :? MethodBase as m in t.GetMethods methodFlags -> m
]
|> printfn "%A"
And that gives me an error on GetConstructors line (translated to English by me)
Incompatibility in type constraint. type MethodBase isn't compatible with type ConstructorInfo.
After a double-check ConstructorInfo derives from MethodBase (and same for MethodInfo).
Note : if I use a flexible type (#MethodBase) instead ; the pattern works but for constructors m has type RuntimeConstructorInfo and for methods m hash type RuntimeMethodInfo (what is the expected behaviour using flexible type). I obviously tested them separately as having a list of two different types isn't allowed.
So question is : Why did I missed/misunderstood ?
The compiler reports the error when you try to use the :? pattern to cast to a supertype from a subtype (an upcast) which is a cast that can never fail. It is worth noting that you get exactly the same error when you use the :? pattern for an upcast anywhere else:
match System.Random() with
| :? obj as o -> o
I think the :? pattern has mainly been intended for safe downcasts (the situation when the pattern matching can fail). For example:
match box 1 with
| :? string as s -> "string"
| :? int as n -> "int"
The compiler checks whether the type you're casting to (here string and int) is a valid subtype of the type used in the parameter (here object).
Converting string to object (or ConstructorInfo to MethodBase) would also be valid, but for a different reason - and the compiler apparently only does the more common kind of check.
Your attempt to use :? definitely makes a lot of sense to me - and I think the check in the compiler could be relaxed to allow this. You can post this as a suggestion to the F# user voice.
This active pattern compiles with F# 2.0:
let (|Value|_|) value = // 'a -> 'T option
match box value with
| :? 'T as x -> Some x
| _ -> None
but, in F# 3.0, emits the error:
Active pattern '|Value|_|' has a result type containing type variables that are not determined by the input. The common cause is a [sic] when a result case is not mentioned, e.g. 'let (|A|B|) (x:int) = A x'. This can be fixed with a type constraint, e.g. 'let (|A|B|) (x:int) : Choice = A x'
I tried:
let (|Value|_|) value : 'T option = ...
and:
let (|Value|_|) (value: 'U) = ...
How can it be fixed?
Environments: Visual Studio 2012 (RTM) and FSI v11.0.50727.1
EDIT: Here's a simpler repro:
let (|X|) x = unbox x
There was a bug in the F# 2.0 compiler where the compiler did incorrect analysis and bad code generation for certain Active Patterns with free type variables in the result; a simple repro is
let (|Check|) (a : int) = a, None
//let (|Check|) (a : int) = a, (None : int option)
let check a =
match a with
| Check (10, None) -> System.Console.WriteLine "10"
| Check (20, None) -> System.Console.WriteLine "20"
check 10
check 20
which generates a weird warning at compile-time and compiles into seemingly incorrect code. I am guessing that our attempt to fix this bug (and restrict some crazy cases) in F# 3.0 also broke some legal code as collateral damage of the fix.
I'll file another bug, but for F# 3.0, it sounds like you'll need to use one of the workarounds mentioned in other answers.
I did not install the new version yet, but I agree this looks a bit fishy. I guess there may be a good reason for this restriction, but your example in the other question seems quite compeling.
As a workaround, I think that adding a witness parameter (that is not used, but hints what the type of the result is going to be) could work:
let (|Value|_|) (witness:unit -> 'T) value : 'T option =
match box value with
| :? 'T as x -> Some x
| _ -> None
Of course, this makes the use a bit uglier, because you need to come up with some argument. In the above, I used witness of type unit -> 'T, hoping that the following might compile:
let witness () : 'T = failwith "!"
match box 1 with
| Value witness 1 -> printfn "one"
If that does not work, then you can probably try using witness parameter of type 'T (but then you have to provide an actual function, rather than just a generic function).
for the sake of completeness, one more workaround:
type Box<'R> = Box of obj
let (|Value|_|) ((Box x) : Box<'R> ) : 'R option =
match x with
| :? 'R as x -> Some x
| _ -> None
let check t =
match Box t with
| Value 1 -> printfn "one"
| Value 2 -> printfn "two"
check 1 // one
check 2 // two
however it still will suffer from the problem mentioned by #kvb in another thread. Personally I'll prefer #kvb's version with parameterized active pattern.
See my answer to your other question for some thoughts on how to work around the issue and one reason that such active patterns might be undesirable. I'm not sure whether the breaking change was intended.
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.
match value with
| :? list<#SomeType> as l -> l //Is it possible to match any list of a type derived from SomeType?
| _ -> failwith "doesn't match"
As already pointed out, there is no way to do this directly (pattern matching can only bind values, but it cannot bind new type variables). In addition to the (more general) workaround by kvb you can use the fact that all collections implement non-generic IEnumerable, so you can check for this type:
match box value with
| :? System.Collections.IEnumerable as l when
// assumes that the actual type of 'l' is 'List<T>' or some other type
// with single generic type parameter (this is not fully correct, because
// it could be other type too, but we can ignore this for now)
typedefof<SomeType>.IsAssignableFrom
(value.GetType().GetGenericArguments().[0]) ->
l |> Seq.cast<SomeType>
| _ -> failwith "doesn't match"
The code tests whether the value is a non-generic IEnumerable and whether the type parameter is subtype of SomeType. In that case, we got a list of some derived type, so we can cast it to a sequence of SomeType values (this is slightly different than working with list of values of the derived types, but it shouldn't matter for practical purposes).
No, it's unfortunately not possible to do something like this - the CLR doesn't provide any efficient way of doing that kind of type test. See How to cast an object to a list of generic type in F# and F# and pattern matching on generics in a non-generic method implementing an interface for a few (rather ugly) solutions.
I later needed something similar for matching Lazy instances. Here's my solution, in case anyone finds it helpful.
let (|Lazy|_|) (value : obj) =
if box value <> null then
let typ = value.GetType()
if typ.IsGenericType && typ.GetGenericTypeDefinition() = typedefof<Lazy<_>> then
Some(typ.GetGenericArguments().[0])
else None
else None
Usage:
match value with
| Lazy typ when typeof<SomeType>.IsAssignableFrom(typ) -> (value :?> Lazy<_>).Value
| _ -> failwith "not an instance of Lazy<#SomeType>"
According to the F# 2.0 specification, par. 14.5.2 (Solving Subtype Constraints), it will not work, because: "F# generic types do not support covariance or contravariance."
Not the cleanest, but effective:
let matchType<'T> () =
try
let o = Activator.CreateInstance<'T> ()
match box o with
| :? Type1 -> printfn "Type1"
| :? Type2 -> printfn "Type2"
| _ -> failwith "unknown type"
with
| ex -> failwith "%s" (ex.ToString())