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# likeAction
orFunc
, 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
or name the argument as a hint
or force it to pick the 3 argument version:
Aside
In your example,
you would explicitly need to annotate
vMap
because the compiler cannot find out what type the property exists on without another pass. For example,This is one of the reasons why the pipe operator is so useful, because it allows you to avoid type annotations: