So I ran across this tour of F#: https://docs.microsoft.com/en-us/dotnet/articles/fsharp/tour
... and boy howdy is F# interesting! The very beginning of the tour defined a sample function, which looks pretty straightforward:
/// You use 'let' to define a function. This one accepts an integer argument and returns an integer.
/// Parentheses are optional for function arguments, except for when you use an explicit type annotation.
let sampleFunction1 x = x*x + 3
So this makes sense to me. It defines what the function is so if I were to pass some number into this thing, it squares it and adds 3 to that result, as seen by the next line in the tour:
/// Apply the function, naming the function return result using 'let'.
/// The variable type is inferred from the function return type.
let result1 = sampleFunction1 4573
After giving this a few more minutes of thought, I came up with the conclusion that C# can do this too! I sure do love C# a whole lot. This is what the above would look like in C# as far as I can tell:
Func<int, int> sampleFunction1 = x => x*x + 3;
var result = sampleFunction1(4573);
So my main question is, what is the difference between what I wrote in C# and what the F# tour showed me? Sub-questions are: Is the IL code any different even though it's the same CLR? What are a few reasons I would use F# over C#?
Technically, these are equivalent. The IL might be a tad different, just because these are different compilers, but not much. In essence these are compiled in the same way.
But C# can't do exactly that. Did you notice how you had to write Func<int,int>
in front? But that's just a very small toy function. What would happen in more practical cases? Observe:
// F#
let f x m = Map.find (x, x+1) m |> Seq.map ((+) 1)
// C#
Func<int, IDictionary<Tuple<int, int>, IEnumerable<int>>, IEnumerable<int>> f = (x, m) => m[Tuple.Create(x, x+1)].Select( i => i+1 );
Fun, isn't it?
This is called "type inference". As in, F# is able to infer types of stuff based on how stuff is used. You can almost write a full program and never once use a type annotation. C# has this too, to some limited extent. That's how I'm able to call .Select( i => i+1 )
, and C# knows that i
is int
, because whatever came before .Select
was IEnumerable<int>
. But it's very limited, not nearly as powerful.
Type inference is just one of the many benefits of F#. I picked it, because you were looking right at it and not seeing it. But there are many more. Order of compilation, lack of nulls, immutability by default, algebraic data types, automatic currying and partial application... Much more, in fact, than will fit in a SO answer.
Those who wish to discover the wonderful and exciting world of functional programming in general and F# in particular, I usually send right off to https://fsharpforfunandprofit.com/, into Mr. Wlaschin's kind and capable hands. A wonderful resource, read it all.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With