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, [])
Related
In this snippet, the current (4.1) compiler complains that it can't determine which overload to Convert to use (a type annotation may be needed), but it recognizes s as a string. Why?
let wtf (list:string List) =
List.map (fun s -> System.Convert.ToInt32(s)) list
As mentioned in the comments, the compiler uses single pass over the code to determine the types. This means that it will report an error (e.g. when it cannot determine which overload to use) as it passes over the problematic code. If it later finds more information, the additional information is not used.
This is exactly what is happening here. Consider:
let wtf (list:string List) =
List.map (fun s -> s) list
Here, the type of s is string and everything works fine. However, when checking fun s -> s, the compiler does not yet know that the type of s is string and it treats it as a value of type variable 'a - it checks the type of function as 'a -> 'a and later unifies 'a with string. Going back to your case:
let wtf (list:string List) =
List.map (fun s -> System.Convert.ToInt32(s)) list
When checking the lambda, the compiler knows s is of type 'a and it fails to resolve the overload of ToInt32. It reports the error, skips the sub-expression and continues (to get as useful IntelliSense as it can) and it later figures out that s was actually string. This appears in the IntelliSense, but it does not undo the error.
Just for the record, the best way to avoid this is to use |> and put the list input first:
let awesome (list:string List) =
list |> List.map (fun s -> System.Convert.ToInt32(s))
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.
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) ##> )
I have a property that tests a type can be successfully round tripped to JSON and back.
let roundTrip<'a when 'a : equality> (x: 'a) = (toJSON >> ofJSON) x = x
which I currently run by calling
Check.Quick roundTrip<TypeName>
What I would like is to be able to run this property over a list of types that I get through reflection (scanning my assembly for types I know need to be JSON serializable)
Is it possible to run this property for types I have in a list at runtime rather that needing to specify them all in my test?
Supposing all of your types either have a custom generator defined for them, or can be derived by the built-generators, all you really need to do is instantiate a MethodInfo of the roundtrip method for each type you want to test. Then there is an overload Check.Method which you call for each of the types. That will run the standard FsCheck tests as if you would've called the method with the type at compile time.
Something like: (sorry, uncompiled, but should be close)
type Marker = class end
let roundtrip<'a> = //as above
let checkForTypes (ts:seq<Type>) =
let roundtripInfo = typeof<Marker>.DeclaringType.GetMethod("roundtrip")
ts
|> Seq.map (fun t -> roundtripInfo.MakeGenericMethod([|t|]))
|> Seq.iter (fun m -> Check.Method(Config.Quick, m))
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 :-)