How do I access the (runtime) instance from the implementation of the a ProvidedMethod
that is if foo is of a provided type and the erased type is Bar with a method named Execute
Then given this code
foo.Execute()
I wish the ProvidedMethod to equal this
bar.Execute() //where bar is an object of type Bar
What I have is this
//p is a MethodInfo that represents Bar.Execute and m is the ProvidedMethod
objm.InvokeCode <- fun args -> <## p.Invoke(--what goes here--,null) ##>
The instance is passed as the first expression in the args array, so you can access it from there.
Also, the InvokeCode that you need to build should not capture the method info p and call Invoke on it using reflection. Instead, you need to build an F# quotation (akin to expression tree) that represents the invocation.
So, you need to write something like this:
objm.InvokeCode <- (fun args ->
// The 'args' parameter represents expressions that give us access to the
// instance on which the method is invoked and other parameters (if there are more)
let instance = args.[0]
// Now we can return quotation representing a call to MethodInfo 'p' with 'instance'
Expr.Call(instance, p) )
Note that I did not use <## .. ##> here because you already have MethodInfo for the method that you want to call. If you instead wanted to call a method ProviderRuntime.DoStuff(instance) then you could use quotation literals:
objm.InvokeCode <- (fun args ->
let instance = args.[0]
<## ProviderRuntime.DoStuff(%%instance) ##> )
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.
given
[
1,"test2"
3,"test"
]
|> dict
// turn it into keyvaluepair sequence
|> Seq.map id
|> fun x -> x.ToDictionary<_,_,_>((fun x -> x.Key), fun x -> x.Value)
which fails to compile if I don't explicitly use the <_,_,_> after ToDictionary.
Intellisense works just fine, but compilation fails with the error: Lookup on object of indeterminate type based on information prior to this program point
So, it seems, Intellisense knows how to resolve the method call.
This seems to be a clue
|> fun x -> x.ToDictionary<_,_>((fun x -> x.Key), fun x -> x.Value)
fails with
Type constraint mismatch.
The type 'b -> 'c is not compatible with type IEqualityComparer<'a>
The type 'b -> 'c' is not compatible with the type 'IEqualityComparer<'a>'
(using external F# compiler)
x.ToDictionary((fun x -> x.Key), id)
works as expected as does
let vMap (item:KeyValuePair<_,_>) = item.Value
x.ToDictionary((fun x -> x.Key), vMap)
I've replicated the behavior in FSI and LinqPad.
As a big fan of and avid reader of Eric Lippert I really want to know
what overload resolution, (or possibly extension methods from different places) are conflicting here that the compiler is confused by?
Even though the types are known ahead, the compiler's getting confused between the overload which takes an element selector and a comparer. The lambda compiles to FSharpFunc rather than the standard delegate types in C# like Action or Func, and issues do come up translating from one to the other. To make it work, you can :
Supply a type annotation for the offending Func
fun x -> x.ToDictionary((fun pair -> pair.Key), (fun (pair : KeyValuePair<_, _>) -> pair.Value)) //compiles
or name the argument as a hint
fun x -> x.ToDictionary((fun pair -> pair.Key), elementSelector = (fun (pair) -> pair.Value))
or force it to pick the 3 argument version:
x.ToLookup((fun pair -> pair.Key), (fun (pair) -> pair.Value), EqualityComparer.Default)
Aside
In your example,
let vMap (item:KeyValuePair<_,_>) = item.Value
x.ToDictionary((fun x -> x.Key), vMap)
you would explicitly need to annotate vMap because the compiler cannot find out what type the property exists on without another pass. For example,
List.map (fun x -> x.Length) ["one"; "two"] // this fails to compile
This is one of the reasons why the pipe operator is so useful, because it allows you to avoid type annotations:
["one"; "two"] |> List.map (fun x -> x.Length) // works
List.map (fun (x:string) -> x.Length) ["one"; "two"] //also works
The short answer:
The extension method ToDictionary is defined like this:
static member ToDictionary<'TSource,_,_>(source,_,_)
but is called like this:
source.ToDictionary<'TSource,_,_>(_,_)
The long answer:
This is the F# type signature of the function you are calling from msdn.
static member ToDictionary<'TSource, 'TKey, 'TElement> :
source:IEnumerable<'TSource> *
keySelector:Func<'TSource, 'TKey> *
elementSelector:Func<'TSource, 'TElement> -> Dictionary<'TKey, 'TElement>
But I only specified two regular parameters: keySelector and elementSelector. How come this has a source parameter?!
The source parameter is actually not put in the parenthesis, but is passed in by saying x.ToDictionary, where x is the source parameter. This is actually an example of a type extension. These kinds of methods are very natural in a functional programming language like F#, but more uncommon in an object oriented language like C#, so if you're coming from the C# world, it will be pretty confusing. Anyway, if we look at the C# header, it is a little easier to understand what is going on:
public static Dictionary<TKey, TElement> ToDictionary<TSource, TKey, TElement>(
this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector,
Func<TSource, TElement> elementSelector
)
So the method is defined with a "this" prefix on a first parameter even though it is technically static. It basically allows you to add methods to already defined classes without re-compiling or extending them. This is called prototyping. It's kinda rare if you're a C# programmer, but languages like python and javascript force you to be aware of this. Take this example from https://docs.python.org/3/tutorial/classes.html:
class Dog:
tricks = [] # mistaken use of a class variable
def __init__(self, name):
self.name = name
def add_trick(self, trick):
self.tricks.append(trick)
>>> d = Dog('Fido')
>>> e = Dog('Buddy')
>>> d.add_trick('roll over')
>>> e.add_trick('play dead')
>>> d.tricks # unexpectedly shared by all dogs
['roll over', 'play dead']
The method add_trick is defined with self as a first parameter, but the function is called as d.add_trick('roll over'). F# actually does this naturally as well, but in a way that mimics the way the function is called. When you declare:
member x.doSomething() = ...
or
member this.doSomething() = ...
Here, you are adding function doSomething to the prototype (or class definition) of "x"/"this". Thus, in your example, you actually have three type parameters, and three regular parameters, but one of them is not used in the call. All you have left is to declare the key selector function, and the element selector function, which you did. That's why it looks weird.
I'm trying to build my first toy-like Type Provider. What I'm trying to achieve is to have dynamically generated properties of dynamically generated types.
collection
|> getItems
|> Seq.map(fun mapItem ->
let nestedType = ProvidedTypeDefinition(assembly, ns, "MyNestedType", None)
let ctor = ProvidedConstructor(List.Empty)
nestedType.AddMember ctor
mapItem.Value
|> Seq.map(fun pair ->
ProvidedProperty(fst(pair), typeof<string>,
GetterCode = fun [_] -> <## snd(pair) ##>))
|> Seq.toList
|> nestedType.AddMembers
ProvidedProperty(mapItem.Key, nestedType,
GetterCode = fun [map] ->
// ?? Runtime Exception
let inst = nestedType.GetConstructors().[0].Invoke([||])
<## inst ##>
))
|> Seq.toList
|> ty.AddMembers
ty
How should I instantiate dynamically generated type ?
I'm assuming this is an erasing type provider (those are the easy ones, so they're better choice for getting started). If that's not the case, then disregard my answer.
In the GetterCode, you do not need to create instance of the nested provided type. You just need to create an instance of the type that it is erased to.
In your case, nestedType is erased to None and so the constructor just needs to create a System.Object value, so you should be able to use:
ProvidedProperty(mapItem.Key, nestedType,
GetterCode = fun [self] -> <## obj() ##>)
In reality, you'll probably want to erase to some type that lets you keep some data that the nested type is supposed to access. If the nested type was erased to, say, MyRuntimeType, you could then write:
let parameter = mapItem.WhateverYouWantHere
ProvidedProperty(mapItem.Key, nestedType,
GetterCode = fun [self] -> <## MyRuntimeType(parameter) ##>)
Note that I'm using let to capture the value of the primitive parameter type, so that the compiler can serialize the quotation (you cannot capture complex object types in a quotation).
What you're trying to do here is instantiate your type while building the provider, and then include that new instance in the body of the property. It should be abundantly clear that you can't instantiate the provided type before you've finished providing it.
What you really want to do is take your provided constructor and build a quotation that calls it. You can't have the compiler build the quotation for you, because in order for the compiler to compile the body of the quotation, it needs to "see" all types/methods/functions inside, and your type is not yet ready. But you can create the quotation manually by using the various constructors under Quotations.Expr. In this case, NewObject is suitable:
GetterCode = fun [map] -> Expr.NewObject (ctor, [])
I am running into difficulty with F# in numerous scenarios. I believe I'm not grasping some fundamental concepts. I'm hoping someone can track my reasoning and figure out the (probably many) things I'm missing.
Say I'm using Xunit. What I'd like to do is, provided two lists, apply the Assert.Equal method pairwise. For instance:
Open Xunit
let test1 = [1;2;3]
let test2 = [1;2;4]
List.map2 Assert.Equal test1 test2
The compiler complains that the function Equal does not take one parameter. As far as I can tell, shouldn't map2 be providing it 2 parameters?
As a sanity check, I use the following code in f# immediate:
let doequal = fun x y -> printf "result: %b\n" (x = y)
let test1 = [1;2;3]
let test2 = [1;2;4]
List.map2 doequal test1 test2;;
This seems identical. doequal is a lambda taking two generic parameters and returning unit. List.map2 hands each argument pairwise into the lambda and I get exactly what I expected as output:
result: true
result: true
result: false
So what gives? Source shows Xunit.Equal has signature public static void Equal<T>(T expected, T actual). Why won't my parameters map right over the method signature?
EDIT ONE
I thought two variables x and y vs a tuple (x, y) could construct and deconstruct interchangeably. So I tried two options and got different results. It seems the second may be further along than the first.
List.map2 Assert.Equal(test1, test2)
The compiler now complains that 'Successive arguments should be separated spaces or tupled'
List.map2(Assert.Equal(test1, test2))
The compiler now complains that 'A unique overload method could not be determined... A type annotation may be needed'
I think that part of the problem comes from mixing methods (OO style) and functions (FP style).
FP style functions have multiple parameters separated by spaces.
OO style methods have parens and parameters separated by commas.
Methods in other .NET libraries are always called using "tuple" syntax (actually subtly different from tuples though) and a tuple is considered to be one parameter.
The F# compiler tries to handle both approaches, but needs some help occasionally.
One approach is to "wrap" the OO method with an FP function.
// wrap method call with function
let assertEqual x y = Assert.Equal(x,y)
// all FP-style functions
List.map2 assertEqual test1 test2
If you don't create a helper function, you will often need to convert multiple function parameters to one tuple when calling a method "inline" with a lambda:
List.map2 (fun x y -> Assert.Equal(x,y)) test1 test2
When you mix methods and functions in one line, you often get the "Successive arguments should be separated" error.
printfn "%s" "hello".ToUpper()
// Error: Successive arguments should be separated
// by spaces or tupled
That's telling you that the compiler is having problems and needs some help!
You can solve this with extra parens around the method call:
printfn "%s" ("hello".ToUpper()) // ok
Or sometimes, with a reverse pipe:
printfn "%s" <| "hello".ToUpper() // ok
The wrapping approach is often worth doing anyway so that you can swap the parameters to make it more suitable for partial application:
// wrap method call with function AND swap params
let contains searchFor (s:string) = s.Contains(searchFor)
// all FP-style functions
["a"; "b"; "c"]
|> List.filter (contains "a")
Note that in the last line I had to use parens to give precedence to contains "a" over List.filter
public static void Equal<T>(T expected, T actual)
doesn't take two parameters - it takes one parameter, which is a tuple with two elements: (T expected, T actual).
Try this instead:
List.map2 Assert.Equal(test1, test2)
It's all there in the type signatures.
The signature for Assert.Equals is something along the lines of 'a * 'a -> unit. List.map2 expects a 'a -> 'b -> 'c.
They just don't fit together.
List.map2 (fun x y -> Assert.Equal(x,y)) test1 test2 - works because the lambda wrapping Equals has the expected signature.
List.zip test1 test2 |> List.map Assert.Equal - works because you now have a single list of tuples, and since List.map wants an 'a -> 'b function (where 'a is now a tuple), Assert.Equal is now fair game.
It's simply not true that two values and a tuple are implicitly interchangeable. At least not as far as F# the language is concerned, or the underlying IL representation is concerned. You can think that it's that way when you call into F# code from, say, C# - an 'a -> 'b -> 'c function there is indeed called the same way syntactically as an 'a * 'b -> 'c function - but this is more of an exception than a rule.
According to its signature Xunit.Assert.Equal() takes a single 2 values tuple parameter
I'm trying to implement a typeprovider using the examples I found in different places.
What I want is to be able to create a constructor which assigns the provided arguments to the right properties. The result will have do the same thing as the type below.
type SomeType(arg1: int, arg2: string) =
member this.Arg1 = arg1
member this.Arg2 = arg2
I've tried different approaches, but I just can't get passed the first argument in the args list.
ProvidedConstructor(
parameters = parameters,
InvokeCode = (fun args -> ??)
What kind of code must be invoked to achieve this. Or do I have to take another approach?
What will be the underlying runtime representation of your provided type (the type you passed to the ProvidedTypeDefinition baseType argument)? The ProvidedConstructor InvokeCode is a function that takes a list of expressions and returns an expression of the underlying type. For example, if the runtime representation is a 2-element tuple, InvokeCode would be something like this:
InvokeCode = (fun [arg1;arg2] -> <## (%%arg1:int), (%%arg2:string) ##>)
Make sure to read this tutorial