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.
Related
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.
What does "^" mean when it's in front of a type?
Example:
int : ^T -> int
string : ^T -> string
this indicates an Statically Resolved Type Parameter
from MSDN:
A statically resolved type parameter is a type parameter that is
replaced with an actual type at compile time instead of at run time.
They are preceded by a caret (^) symbol.
so it's very similar to 'T but you can use it to give member constraints and the compiler will resolve them at compile-time (obviously) - usually you are just using inline and the type-inference will work it out for you - but there are some quite advanced tricks (for example FsControl) out there using this (not often used) feature
example
let inline add a b = a + b
val inline add :
a: ^a -> b: ^b -> ^c
when ( ^a or ^b) : (static member ( + ) : ^a * ^b -> ^c)
will add such a constraint to indicate that this will work with all numeric types (it will add an member constraint to an static operator (+))
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.
I'm attempting to use explicit member constraints in F#. The documentation says "F# supports the complete set of constraints that is supported by the common language runtime", but if I actually compile a class with such an explicit constraint, such as the following, I get quite the exotic error.
type MyType<'T when ^T: (static member ( + ) : ^T * ^T -> ^T)> =
member this.F a b = a + b
reports
error FS0670: This code is not sufficiently generic. The type variable ^T when ^T : (static member ( + ) : ^T * ^T -> ^T) could not be generalized because it would escape its scope.
And reports it at the site of defining member this.F. What does this mean? What is the relevant scope?
There are a number of approaches supported by the language for doing this sort of work. A nice exploration can be found here on StackOverflow, but I've not seen a clear explanation of why this particular generic constraint is not allowed to 'escape'.
Member constrains need statically resolved type parameters. But statically resolved type parameters are not allowed on types (as in your example), only for inline functions and inline methods.
The underlying problem is probably that types as a whole cannot be inline.
See also: http://msdn.microsoft.com/en-us/library/dd548046.aspx
If you use an inline member like this:
type MyType() =
member inline this.F a b = a + b
the types of a and b will automatically be correctly constrained.
You need to mark the member inline (and add type annotations if you want to force the arguments to be of type ^T):
type MyType<'T when ^T: (static member ( + ) : ^T * ^T -> ^T)>() =
member inline this.F (a:^T) (b:^T) = a + b
I've also added a constructor, so that you can actually call the method:
MyType().F 1 2
As others have noted, it is rarely necessary to write out the explicit member constraints by hand since they will usually be inferred. Furthermore, in this case there's no reason to put the constraint on the type rather than the method, and having a type parameterized by a statically resolved type variable is not idiomatic.
F# specification:
A type of the form ^ident is a
statically resolved variable type. A
fresh type inference variable is
created and added to the type
inference environment (see §14.6).
This type variable is tagged with an
attribute indicating it may not be
generalized except at inline
definitions (see §14.7), and likewise
any type variable with which it is
equated via a type inference equation
may similarly not be generalized.
http://research.microsoft.com/en-us/um/cambridge/projects/fsharp/manual/spec.html
I am trying to explore the type of operators such as :: in F# interactive.
But I get these kinds of messages:
Unexpected symbol '::' in expression. Expected ')' or other token.
even if I surround it with (::).
I do it like this:
> let inline showmecons a b = a :: b;;
val inline showmecons : 'a -> 'a list -> 'a list
or
> let inline showmepow a b = a ** b;;
val inline showmepow :
^a -> ^b -> ^a when ^a : (static member Pow : ^a * ^b -> ^a)
You'll see the type of usual operators if you surround them with parentheses:
> (+);;
val it : (int -> int -> int) = <fun:it#4-5>
Unfortunatelly, this restricts the type of the operator to one specific type - F# Interactive doesn't print the polymorphic definition (with constraints). You can use the workaround suggested by Stephen (and define a new inline function) to see that.
The reason why it doesn't work for :: is that :: is actually a special syntactic construct (defined directly in the F# specification).
This is pretty old, but I'm learning F# and also wanted to figure this out.
Looking at the F# specification on page 32, we see that symbolic keywords also have a compiled name in F#. The equivalent compiled name for :: is op_ColonColon, which actually accepts tuples:
> op_ColonColon;;
val it : arg0:'a * arg1:'a list -> 'a list = <fun:clo#22-5>`
Using :: to define an inline function will give us a curried cons function, which is misleading, I believe.