In F#, is there any difference whatsoever between let f = fun a -> a-1
and let f a = a-1
? As far as I can see, the latter is simply syntactic s
(fun a -> ...)
is simply an anonymous function. F# differs from C# in that functions are first class citizens, so when you bind an anonymous function to f
, it will give f
the type signature val f : int -> int
(because a
is inferred to be int32
), just as if you had bound a normal, named function as in your second example. You can prove that they are semantically identical by running your examples in F# interactive.
Edit: Anonymous functions even support generics which are normally inferred but can be made explicit, like this:
let f<'T> = (fun (x: 'T) -> x)
Edit 2: From the F# 3.1 spec draft (found here):
A value definition is considered a function definition if its immediate right-hand-side is an anonymous function, as in this example:
let f = (fun w -> x + w)
Setting the obvious syntax error aside, what this is saying is that binding a function value (i.e. anonymous function) to an identifier is literally equivalent to a normal function definition. It goes on to say that this equivalence is a "staple of functional programming," so you can be pretty sure this won't change in the future.
For general purposes, F# treats function definitions and function values (i.e. delegate instances, anonymous functions) as equal at design time, but when it needs to lift a function definition to a function value, it will use the delegate type FSharpFunc as the compiled type. This is the case for all higher order functions, like those in the Array, List, Seq modules, and so forth, since there's no actual way to use a CIL method as a function value like you can with delegates. Everything else looks exactly like you'd expect compiled C# or VB.NET to -- it's just delegates for which F# uses FSharpFunc.
Edit 3: I'm not able to add comments yet, but with regards to Tomas' answer, the F# compiler doesn't know how to generalize the expression let h = (); fun a -> a
but it will accept it if you add the type annotations yourself, like with Nikon's id
example.
Edit 4: Here's an awesomely crude picture of how F# compiles functions. Notice how Tomas' example, a sequencing expression as he called it, gets turned into an FSharpFunc, whereas the equivalent function without the ();
becomes an actual CIL method. This is what the F# spec was talking about above. Also, when you use a regular CIL method as a value, with partial application or otherwise, the compiler will make a FSharpFunc to represent it as a closure.