type inference in F# - f#

In F# why does my add function not add two floats
let add a b = a+b
(add 3 4) //returns 7
(add 3.5 5.5) //error
also please explain how type inference works in F#.
Thanks.

You have to make it inline.
let inline add a b = a+b
The problem is that + is an inline operator, so if your function add is not inline it will take the default overload which is for int.
Have a look at this answer Use of `inline` in F#
When the function is declared inline, type inference will infer the static type constraints.
val inline add :
^a -> ^b -> ^c
when ( ^a or ^b) : (static member ( + ) : ^a * ^b -> ^c)
So now a and b could be any type that implement the static member (+) with that signature.

If you only want your function to work with floats use a type annotation.
let add (a:float) b = a + b //float -> float -> float

In F#, the type inference system just puts a type of int when you are dealing with numbers, due to technical restrictions.
In Haskell, add :: Num a => a -> a -> a works because of typeclasses, which is different from .NET classes. Typeclasses do not fit F#.
See http://en.wikibooks.org/wiki/F_Sharp_Programming/Basic_Concepts#Type_Inference and http://en.wikibooks.org/wiki/F_Sharp_Programming/Values_and_Functions

My two cents here.
Actually if you change the order of the execution to,
let add a b = a+b
(add 3.5 5.5) //returns 9.0
(add 3 4) //error
You will see that F# does do add to two floats. ( This answers your question In F# why does my add function not add two floats )
And notice that in this snippet, F# infers the function add type as float -> float -> float.
Why F# infers function type differently in the two cases even you define the function in the exact same way?
I think that when you define the function, F# gives the type int to the function. But internally, F# remains flexible about the "true" type of the function. The first time/line you call the function, the compiler sees how you use it and thus your "intention" of the function type is understood by the compiler. And the compiler adjust the type accordingly.
Once the compiler "thinks" it gets the "true type" of the function, it is what it is. And due to that F# is statically typed, you cannot make a second call to the function with a different type of argument.
That being said, I recommend you try these snippet.
let add a b = a + b
add "str" "ing"
It should work.
let add a b = a + b
add 5. 6.
add "str" "ing" // error, check the type
Correct me if I am wrong. Hope this helps.

Related

F# type inference with Array.sum

Why do I have to tell F# whether I am using a int or float in this line
let total counts = Array.sum counts to let total (counts:int[]) = Array.sum counts ?
Coming from sml I am finding F# type inference a bit too restrictive.
P.S. I don't know much about the landscape of functional languages but would be interested if someone could enlighten me which F-languages are used out in the wild.
In F# compilation is single pass and (mostly) strictly feed-forward. I believe this is done to improve compile times but I'm not sure. The result is that in the expression Array.sum counts the sum function doesn't know what type counts is unless you add a type annotation.
You can write the computationally equivalent expression counts |> Array.sum and because counts appears earlier in the file sum is able to resolve the type correctly. This is one of the reasons the pipeline operator |> is so common in F# code.
(The rec and and keywords allows the compiler to to refer to things forward in the source file to permit mutually recursive functions and types and members within class definitions are mutually recursive by default but this is the exception.)
Not a direct answer but you have the option of creating an inline function which will be more generic:
let inline total counts = Array.sum counts
The type of this automatically gets inferred with the necessary statically resolved type parameters:
> val inline total:
counts: ^a[] -> ^a
when ^a: (static member (+) : ^a * ^a -> ^a) and
^a: (static member get_Zero: -> ^a)
Usage:
total [|1; 2; 3|] // 6
total [|1.; 2.; 3.|] // 6.0
According to the error message I get the problem is that you have to constrain it to a type that support the '+' operator.
I assume that both float and int does that but not the default type 'obj' which is the type you get if you don't specify the type of the array.

Why does the argument type of arithmetic operators default to int?

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.

Why isn't it possible to use the same function twice with differently typed arguments?

I played around a little with F# today, wrote this:
let sq x = x * x
let i = sq 3
let d = sq 3.0
It compiles if I remove either the third or the fourth line, but not if both are present.
I get the error This expression should have type 'int', but has type 'float'.
The type inference works so that your function sq has type int -> int, because the first time compiler sees you use that function, you pass it an integer. So it assumes that sq is a function that takes an integer, and by definition of the function (x * x) it also returns an integer.
It is a bit complicated to define a fully generic arithmetic function in F#, but one way to do it is to make the function inline, like so:
let inline sq x = x * x
This way the body of your function will be inlined each time at the call site, so using an inlined sq function will be the same as substituting it's body every time it's used.
This approach has it's drawbacks, and I think it will be interesting for you to see this question.
Let-bound functions cannot be overloaded. In your specific case, you could use inline, which inlines the function body at compile time and can therefore choose an appropriate implementation of *, e.g.
let inline sq x = x * x
The other answers are correct but they leave out an important part of the jigsaw: the fact that in F# there are no implicit conversions between, for example, ints and floats. This is the reason why your second call is in effect calling a different, non existent, overload with a float argument.
The function let sq x = x * x on default has type int -> int.
If you put it in the context of a let d = sq 3.0, F# compiler will infer its type as float -> float.
In any way, this function can have only one type signature, either int->int, or float->float.
This is a limitation in how the bindings are implemented. There are 2 alternatives.
Firstly, add inline to the declaration.
Secondly, use member bindings in a class and override the different types.

Two simple F# questions

There are two snippets of F# I would like to understand, but don't know what to google. First:
let ``1+2`` () = ....
I am guessing this just means "turn the expression into an identifier"? But what is that feature called if I want to refer to it?
Second, what does the character ^ mean when it occurs in a type? I have found several mentions of it, but the explanation always just says "the type is this" rather than "it differs from a type without a 1^1 in that ...". For example:
let inline blah x y = x+y;;
val inline blah :
^a -> ^b -> ^c
when ( ^a or ^b) : (static member ( + ) : ^a * ^b -> ^c)
Many thanks in advance.
I'd probably call that a "quoted identifier" http://research.microsoft.com/en-us/um/cambridge/projects/fsharp/manual/spec.html#_Toc270597387
"Statically resolved type parameter" http://msdn.microsoft.com/en-us/library/dd548046%28VS.100%29.aspx
The backquote syntax is indeed just a way to 'quote' arbitrary characters into identifiers, I am not sure if it has a name. It is typically used for e.g.
let ``This Identifier Contains Spaces`` = 42
or
foo.``member``(42) // 'member' is an F# keyword, but maybe it was the name of some
// method from C# code you're using, so here's a way to call it
The carat indicates a statically resolved type parameter:
http://msdn.microsoft.com/en-us/library/dd548046.aspx
used for ad-hoc overloading/genericity.

Use of `inline` in F#

The inline keyword in F# seems to me to have a somewhat different purpose than what I'm used to in e.g. C. For example, it seems to affect a function's type (what are "statically resolved type parameters"? Aren't all F# types resolved statically?)
When should I be using inline functions?
The inline keyword indicates that a function definition should be inserted inline into any code which uses it. Most of the time, this will not have any effect on the type of the function. However, in rare cases, it can lead to a function which has a more general type, since there are constraints which cannot be expressed in the compiled form of the code in .NET, but which can be enforced when the function is being inlined.
The primary case where this applies is the use of operators.
let add a b = a + b
will have a monomorphic inferred type (probably int -> int -> int, but it could be something like float -> float -> float if you have code which uses this function at that type instead). However, by marking this function inline, the F# compiler will infer a polymorphic type:
let inline add a b = a + b
// add has type ^a -> ^b -> ^c when ( ^a or ^b) : (static member ( + ) : ^a * ^b -> ^c)
There is no way to encode this type constraint in a first class way in compiled code on .NET. However, the F# compiler can enforce this constraint at the site where it inlines the function, so that all operator uses are resolved at compile time.
The type parameters ^a, ^b, and ^c are "statically resolved type parameters", which means that the types of the arguments must be statically known at the site where those parameters are being used. This is in contrast to normal type parameters (e.g. 'a, 'b, etc.), where the parameters mean something like "some type which will be supplied later, but which can be anything".
You should use inline when you need to define a function that must have its type (re)evaluated at the site of each usage, as opposed to a normal function, which will have its type evaluated (inferred) only at the site of first usage, and then be regarded as being statically typed with that first inferred type signature everywhere else thereafter.
In the inline case, the function definition is effectively generic/ polymorphic, whereas in the normal (none-inline) case, the function is statically (and often implicitly) typed.
So, if you use inline, the following code:
let inline add a b = a + b
[<EntryPoint>]
let main args =
let one = 1
let two = 2
let three = add one two
// here add has been compiled to take 2 ints and return an int
let dog = "dog"
let cat = "cat"
let dogcat = add dog cat
// here add has been compiled to take 2 strings and return a string
printfn "%i" three
printfn "%s" dogcat
0
will compile, build and run to produce the following output:
3
dogcat
In other words, the same add function definition has been used to produce both a function that adds two integers, and a function that concatenates two strings (in fact the underlying operator overloading on + is also achieved under the hood using inline).
Whereas this code, identical except that the add function is no longer declared inline:
let add a b = a + b
[<EntryPoint>]
let main args =
let one = 1
let two = 2
let three = add one two
// here add has been compiled to take 2 ints and return an int
let dog = "dog"
let cat = "cat"
let dogcat = add dog cat
// since add was not declared inline, it cannot be recompiled
// and so we now have a type mismatch here
printfn "%i" three
printfn "%s" dogcat
0
will NOT compile, failing with this complaint:
let dogcat = add dog cat
^^^ - This expression was expected to have type int
but instead has type string
A good example of where using inline is appropriate, is when you want to define a high order function (HOF, i.e. a function taking (other) functions as arguments), e.g. a generic function to reverse the order of the application of arguments of a function with 2 arguments, e.g.
let inline flip f x y = f y x
as is done in the answer from #pad to this question Different argument order for getting N-th element of Array, List or Seq.
When should I be using inline functions?
The most valuable application of the inline keyword in practice is inlining higher-order functions to the call site where their function arguments are also inlined in order to produce a singly fully-optimized piece of code.
For example, the inline in the following fold function makes it 5× faster:
let inline fold f a (xs: _ []) =
let mutable a = a
for i=0 to xs.Length-1 do
a <- f a xs.[i]
a
Note that this bears little resemblance to what inline does in most other languages. You can achieve a similar effect using template metaprogramming in C++ but F# can also inline between compiled assemblies because inline is conveyed via .NET metadata.
The F# component design guidelines only mention a little about this. My recommendation (that aligns well with what's said there) is:
Don't use inline
Exception: you might consider using inline when writing mathematical libraries to be consumed by other F# code and you want to write functions that are generic over different numeric data types.
There are lots of other "interesting" uses of inline and static member constraints for "duck-typing" kinds of scenarios that work a bit like C++ templates. My advice is to avoid all of that like the plague.
#kvb's answer goes into more depth about what 'static type constraints' are.

Resources