My problem, in a nutshell, is this:
What can I do about storing a tuple (or any type with a constraint of 'comparison') in a C# container that requires an IComparable?
This works:
> let x (y : 'a when 'a : comparison) = y ;;
val x : y:'a -> 'a when 'a : comparison
> x (1,2) ;;
val it : int * int = (1, 2)
I would have thought this would work:
> let x (y : IComparable<int>) = y ;;
val x : y:IComparable<int> -> IComparable<int>
> x (1,2) ;;
x (1,2) ;;
---^^^
stdin(28,4): error FS0001: The type ''a * 'b' is not compatible with the type 'IComparable<int>'
And this as well:
> let x (y : IComparable) = y ;;
val x : y:IComparable -> IComparable
> x (1,2) ;;
x (1,2) ;;
---^^^
stdin(30,4): error FS0001: The type ''a * 'b' is not compatible with the type 'IComparable'
EDIT
I follow the argument that F# doesn't do implicit upcasting. However, even explicitly:
> (1, 2) :> IComparable ;;
(1, 2) :> IComparable ;;
^^^^^^^^^^^^^^^^^^^^^
stdin(43,1): error FS0193: Type constraint mismatch. The type
int * int
is not compatible with type
IComparable
The type 'int * int' is not compatible with the type 'IComparable'
I suppose this makes sense as the comparability of a F# tuple is inferred structurally within the F# type system, and perhaps that extra information is not available to .NET.
It seems one workaround per a comment below is invoking
Tuple<_,_> (1,2) ;;
Or even
box (1, 2) :?> IComparable ;;
F# does not do implicit upcasting as C# does. If you request an IComparable, then you are requesting an IComparable and not something which can be upcast to IComparable
What you really want, is requesting a type, that happens to implement IComparable, but you are still working with the specific type.
That's why let x (y : 'a when 'a : comparison), see that y is of type 'a, whereas 'a can be statically upcast to comparison (if you want to access a member of comparison, you will have to upcast to comparison using :> first)
On the other hand let x (y : IComparable<int>) = y requests very explicitly a IComparable<int>. But you are passing (1,2), a value, that can be upcast to IComparable. So if you pass (1,2) :> IComparable<int> or even (1,2) :> _, the compiler will be able to pass the value. You can wrap up the comparable, but you lose type information, the return value will be a IComparable and no longer an int*int.
let wrapComparable value =
{
new IComparable with
member this.CompareTo other =
match other with
| :? 'a as other -> compare value other
| _ -> raise <| InvalidOperationException()
}
Also, here you need to consider, that IComparable is based on obj so you probably need to consider the case, where your other is of a different type.
In case, you only need IComparable<'a> the code becomes simpler:
let wrapComparable value =
{
new IComparable<_> with
member this.CompareTo other = compare value other
}
As such, as a rule of thumb, you usually want to make a generic function with type constraints, rather than requesting an interface, as you would in C#. This is due to the fact, that F# does not do automatic upcasting.
A very detailed explanation about equality and comparisons can be found in http://lorgonblog.wordpress.com/2009/11/08/motivating-f-equality-and-comparison-constraints/ and http://blogs.msdn.com/b/dsyme/archive/2009/11/08/equality-and-comparison-constraints-in-f-1-9-7.aspx. Also the MSDN states, that
If you are only using tuples from F# and not exposing them to other languages, and if you are not targeting a version of the .NET Framework that preceded version 4, you can ignore this section.
Tuples are compiled into objects of one of several generic types, all named Tuple, that are overloaded on the arity, or number of type parameters. Tuple types appear in this form when you view them from another language, such as C# or Visual Basic, or when you are using a tool that is not aware of F# constructs. The Tuple types were introduced in .NET Framework 4. If you are targeting an earlier version of the .NET Framework, the compiler uses versions of System.Tuple from the 2.0 version of the F# Core Library. The types in this library are used only for applications that target the 2.0, 3.0, and 3.5 versions of the .NET Framework. Type forwarding is used to ensure binary compatibility between .NET Framework 2.0 and .NET Framework 4 F# components.
So it seems, that the fact, that Tuples, happen to be System.Tuple is really just an implementation detail at which point, the lack of IComparison makes somewhat sense.
Definitely some weirdness going on. FWIW, it works if you construct a System.Tuple<_, _> explicitly, so that might be a workaround:
let x (y : IComparable) = y
let t = (2, 3)
x (Tuple<_,_> t)
Related
let mapTuple f (a,b) = (f a, f b)
I'm trying to create a function that applies a function f to both items in a tuple and returns the result as a tuple. F# type inference says that mapTuple returns a 'b*'b tuple. It also assumes that a and b are of the same type.
I want to be able to pass two different types as parameters. You would think that wouldn't work because they both have to be passed as parameters to f. So I thought if they inherited from the same base class, it might work.
Here is a less generic function for what I am trying to accomplish.
let mapTuple (f:Map<_,_> -> Map<'a,'b>) (a:Map<int,double>,b:Map<double, int>) = (f a, f b)
However, it gives a type mismatch error.
How do I do it? Is what I am trying to accomplish even possible in F#?
Gustavo is mostly right; what you're asking for requires higher-rank types. However,
.NET (and by extension F#) does support (an encoding of) higher-rank types.
Even in Haskell, which supports a "nice" way of expressing such types (once you've enabled the right extension), they wouldn't be inferred for your example.
Digging into point 2 may be valuable: given map f a b = (f a, f b), why doesn't Haskell infer a more general type than map :: (t1 -> t) -> t1 -> t1 -> (t, t)? The reason is that once you include higher-rank types, it's not typically possible to infer a single "most general" type for a given expression. Indeed, there are many possible higher-rank signatures for map given its simple definition above:
map :: (forall t. t -> t) -> x -> y -> (x, y)
map :: (forall t. t -> z) -> x -> y -> (z, z)
map :: (forall t. t -> [t]) -> x -> y -> ([x], [y])
(plus infinitely many more). But note that these are all incompatible with each other (none is more general than another). Given the first one you can call map id 1 'c', given the second one you can call map (\_ -> 1) 1 'c', and given the third one you can call map (\x -> [x]) 1 'c', but those arguments are only valid with each of those types, not with the other ones.
So even in Haskell you need to specify the particular polymorphic signature you want to use - this may be a bit of a surprise if you're coming from a more dynamic language. In Haskell, this is relatively clean (the syntax is what I've used above). However, in F# you'll have to jump through an additional hoop: there's no clean syntax for a "forall" type, so you'll have to create an additional nominal type instead. For example, to encode the first type above in F# I'd write something like this:
type Mapping = abstract Apply : 'a -> 'a
let map (m:Mapping) (a, b) = m.Apply a, m.Apply b
let x, y = map { new Mapping with member this.Apply x = x } (1, "test")
Note that in contrast to Gustavo's suggestion, you can define the first argument to map as an expression (rather than forcing it to be a member of some separate type). On the other hand, there's clearly a lot more boilerplate than would be ideal...
This problem has to do with rank-n types which are supported in Haskell (through extensions) but not in .NET type system.
One way I found to workaround this limitation is to pass a type with a single method instead of a function and then define an inline map function with static constraints, for example let's suppose I have some generic functions: toString and toOption and I want to be able to map them to a tuple of different types:
type ToString = ToString with static member inline ($) (ToString, x) = string x
type ToOption = ToOption with static member ($) (ToOption, x) = Some x
let inline mapTuple f (x, y) = (f $ x, f $ y)
let tuple1 = mapTuple ToString (true, 42)
let tuple2 = mapTuple ToOption (true, 42)
// val tuple1 : string * string = ("True", "42")
// val tuple2 : bool option * int option = (Some true, Some 42)
ToString will return the same type but operating with arbitrary types. ToOption will return two Generics of different types.
By using a binary operator type inference creates the static constraints for you and I use $ because in Haskell it means apply so a nice detail is that for haskellers f $ x reads already apply x to f.
At the risk of stating the obvious, a good enough solution might be to have a mapTuple that takes two functions instead of one:
let mapTuple fa fb (a, b) = (fa a, fb b)
If your original f is generic, passing it as fa and fb will give you two concrete instantiations of the function with the types you're looking for. At worst, you just need to pass the same function twice when a and b are of the same type.
I am new to F#, and I was surprised to find that the type of f x y = x + y is actually int -> int -> int. Appearently, this is due to some performance trade-off.
But why is this actually necessary? Why not just infer the type to be 'a -> 'a -> 'a or something similar? It seems to work for comparison: the type of g x y = x < y is x:'a -> y:'a -> bool when 'a : comparison. Why not for arithmetic operators as well?
Couldn't the compiler statically infer the specific primitive types from the call sites and specialize the generic function from there, falling back to some dynamic dispatch if this fails?
This might very well be obvious, but I could not find any good resources on this. What is the reasoning behind this behavior?
Yes, for those operators int is the default type inferred unless you specify a different one or is inferred by the use. If you want to define them for all types you have to make the function inline:
let inline f x y = x + y
But notice that the signature is:
x: ^a -> y: ^b -> ^c
when ( ^a or ^b) : (static member ( + ) : ^a * ^b -> ^c)
This is because in .NET you can't use member constraints but F# resolves them at compile time. That's why you see those 'hat types' and the constraint that those type should have a static member (+) defined.
Also notice the type variables are not a -> a -> a as you suggest, that's because in the .NET framework not all addition operations respect that signature. Things are different in other environments like Haskell, there the addition is strictly a -> a -> a but in .NET you can add for instance a TimeSpan to a DateTime:
System.DateTime(2000,1,1) + new System.TimeSpan(1, 2, 0, 30, 0)
and the result it's a DateTime, here the signature is: a -> b -> a
Comparison is a different story since that constraint actually exists at .NET level so it can be compiled and encoded in the IL whereas member constraints need to be resolved at compile time, that why the function has to be marked as inline.
I think you misinterpreted the explanation in the linked question: this is not due a performance trade-off, the real reason is a .NET type system limitation. The fact that an inline function executes faster in most cases (since it's inlined by the compiler) is a secondary effect.
I had expected that flexible type would minimize the need of explicit upcast, but
type IB =
abstract B : int
type A() =
interface IB with
member this.B = 1
let a = A()
let test (x) = x
let aa = [|a; a|]
let case1 = aa |> Array.map (fun (x: #IB) -> test (x.B))
let case2 = Array.map (fun (x: #IB) -> test (x.B)) aa
Here, there are warnings (less generic than type annotation) on the last 2 lines. The compiler is able to compile case2, but fails at case1, why is that?
It feels odd that the more detailed the compiler can infer, the more code I need to write.
#kvb pointed out there is a simple fix, just to refactor the lambda function into a non inline version.
let fix (x: #IB) =
test x.B
let case1 = aa |> Array.map fix
let case2 = Array.map fix
This works well.
Type inference in F# flows from left to right, so it's not too surprising that piping can break or fix things. However, it's almost always the case that having more type information earlier is helpful, so this result is a bit surprising. The warnings are a subtle indicator that you're doing something wrong. Flexible types seem like they ought to be applicable in many tricky situations, but there are really only a few places where they help. Array.map takes a function of some type 'a -> 'b for some particular 'a and 'b (though there's a little bit of nuance here, since the "particular" types could be type variables), so having a "more generic" argument like #IB -> int is not especially helpful; the compiler will pick some particular subtype of IB during compilation - this is what the warnings are attempting to communicate.
As I said, the different results you see on the different lines are due to the fact that type inference in F# works left to right. In the first case, the information about the type of aa flows into the type checking of the remainder of the expression and so when compiling the lambda the compiler knows that the only possible subtype of IB that will work is A, but because interface implementations are always implicit this causes a compile time error because A doesn't have a publicly available member B. On the other hand, in the second case, when the compiler's trying to check Array.map it doesn't yet know the type of the array it will be applied to, but can check the call in any case because regardless of the subtype it will support the interface method IB.B (implicitly upcasting the argument from whatever subtype of IB it has to just IB). Then when this is applied to aa the compiler specializes the implementation to A, but because of the implicit upcast this still works okay. Intuitively, it seems like the compiler ought to have been able to have inserted the same implicit upcast in the former case, but I think this is probably just a surprising result of the inference algorithm and not an actual bug.
Perhaps more surprising, one possible fix is to just use a let-bound definition (for either the lambda or even as a type-restricted version of Array.map) and skip the flexible type:
let f (x:IB) = test (x.B)
let g (f:IB -> int) = Array.map f
let d' = aa |> g (fun x -> test (x.B))
let d'' = aa |> Array.map f
let c' = g (fun x -> test (x.B)) aa
let c'' = Array.map f aa
So what's happening here? It turns out the compiler does something called "Implicit Insertion of Flexibility for Uses of Functions and Members" (section 14.4.3 of the spec for F# 3.1) which does exactly what you want.
type IB =
abstract B : int
type A() =
interface IB with
member this.B = 1
let a = A()
let test (x) = x
let aa = [|a; a|]
Here the compiler knows that aa is an array of A so type annotation in lambda is not needed but you have to cast x to the interface type because in F# interfaces are implemented explicitely (http://msdn.microsoft.com/en-us/library/ms173157.aspx):
let d = aa |> Array.map (fun x -> test ((x:>IB).B))
Here the compiler at the moment of compiling lambda doesn't know what a type of x is, so you need a type annotation telling that x is implementation of IB interface so you can refer to x.B property directly:
let c = Array.map (fun (x: #IB) -> test (x.B)) aa
In following case
let a = [1]
let f x = x
let b = a |> List.map f
a is an int list. We call List.map so for sure f must be a int->? function. Why is f still typed as 'a ->'a instead of int->int?
If this is how type inference (not)works in F# i see little benefits for it.
Is there an workaround without specifying the type for x in f explicitly?
Lets imagine x has type (A*B*C list ( D option, E list)))
Also another interesting thing:
open System.Collections.Generic
let d = new Dictionary()
d.[1] ="a"
This does not work unless the "new" keyword is removed.
Type inferencing works just fine here. f is inferred as having the type 'a -> 'a, which means that it'll take a value of the generic type 'a and return a value of the same generic type 'a.
In this case, type inferencing kicks in when you use it. Because a has the type int list, and because List.map has the signature ('T -> 'U) -> 'T list -> 'U list, it can infer types from the expression
let b = a |> List.map f
In this case, the 'T list argument is a, so it has the type int list. This means it now knows that 'T is int.
The function passed to List.map has the general form 'T -> 'U, but in this case we pass f, which has the form 'a -> 'a, which is equivalent to 'T -> 'T. Because of this, the compiler understands that in this case, 'T and 'U are the same types.
This means that it can infer that the return type 'U list must also be int list.
The function f is typed 'a -> 'a because it works at every type, not just int:
> f "foo";;
val it = "foo" : string
> f 0.8;;
val it = 0.8 : float
This an advantage: the generic type 'a -> 'a gives you the freedom to use f when it is safe to do so, as opposed to only at the type int -> int.
To add a little something to the fine answers already listed here.
There is one circumstance where you will want to not use the generic inferred type. The generic version of f will be slower than the type specific version. But F# has a keyword for taking care of that for you:
let inline f x = x
Which tells the compiler to use the type specific version of any operations you apply to x. The inferred type will remain generic. You will only need this in time critical section of code.
As noted elsewhere, the generic inference is a useful thing and you'll probably grow to like it.
I thought that conversions between F# functions and System.Func had to be done manually, but there appears to be a case where the compiler (sometimes) does it for you. And when it goes wrong the error message isn't accurate:
module Foo =
let dict = new System.Collections.Generic.Dictionary<string, System.Func<obj,obj>>()
let f (x:obj) = x
do
// Question 1: why does this compile without explicit type conversion?
dict.["foo"] <- fun (x:obj) -> x
// Question 2: given that the above line compiles, why does this fail?
dict.["bar"] <- f
The last line fails to compile, and the error is:
This expression was expected to have type
System.Func<obj,obj>
but here has type
'a -> obj
Clearly the function f doesn't have a signature of 'a > obj. If the F# 3.1 compiler is happy with the first dictionary assignment, then why not the second?
The part of the spec that should explain this is 8.13.7 Type Directed Conversions at Member Invocations. In short, when invoking a member, an automatic conversion from an F# function to a delegate will be applied. Unfortunately, the spec is a bit unclear; from the wording it seems that this conversion might apply to any function expression, but in practice it only appears to apply to anonymous function expressions.
The spec is also a bit out of date; in F# 3.0 type directed conversions also enable a conversion to a System.Linq.Expressions.Expression<SomeDelegateType>.
EDIT
In looking at some past correspondence with the F# team, I think I've tracked down how a conversion could get applied to a non-syntactic function expression. I'll include it here for completeness, but it's a bit of a strange corner case, so for most purposes you should probably consider the rule to be that only syntactic functions will have the type directed conversion applied.
The exception is that overload resolution can result in converting an arbitrary expression of function type; this is partly explained by section 14.4 Method Application Resolution, although it's pretty dense and still not entirely clear. Basically, the argument expressions are only elaborated when there are multiple overloads; when there's just a single candidate method, the argument types are asserted against the unelaborated arguments (note: it's not obvious that this should actually matter in terms of whether the conversion is applicable, but it does matter empirically). Here's an example demonstrating this exception:
type T =
static member M(i:int) = "first overload"
static member M(f:System.Func<int,int>) = "second overload"
let f i = i + 1
T.M f |> printfn "%s"
EDIT: This answer explains only the mysterious promotion to 'a -> obj. #kvb points out that replacing obj with int in OPs example still doesn't work, so that promotion is in itself insufficient explanation for the observed behaviour.
To increase flexibility, the F# type elaborator may under certain conditions promote a named function from f : SomeType -> OtherType to f<'a where 'a :> SomeType> : 'a -> OtherType. This is to reduce the need for upcasts. (See spec. 14.4.2.)
Question 2 first:
dict["bar"] <- f (* Why does this fail? *)
Because f is a "named function", its type is promoted from f : obj -> obj following sec. 14.4.2 to the seemingly less restrictive f<'a where 'a :> obj> : 'a -> obj. But this type is incompatible with System.Func<obj, obj>.
Question 1:
dict["foo"] <- fun (x:obj) -> x (* Why doesn't this, then? *)
This is fine because the anonymous function is not named, and so sec. 14.4.2 does not apply. The type is never promoted from obj -> obj and so fits.
We can observe the interpreter exhibit behaviour following 14.4.2:
> let f = id : obj -> obj
val f : (obj -> obj) (* Ok, f has type obj -> obj *)
> f
val it : ('a -> obj) = <fun:it#135-31> (* f promoted when used. *)
(The interpreter doesn't output constraints to obj.)