I'm new to F# and playing around a bit, I already did work with C#. One thing that recently confused me a bit was returning values in functions. I do unterstand that everything is an expression (as described here) and that the following code won't compile nor execute:
let foo x =
if x = 0 then x + 2 //The compiler will complain here due to a missing else branch.
x - 2
Instead, you would have to write that:
let foo x =
if x = 0 then x + 2
else x - 2
I do see why that is and a similar problem also occurs when having a loop.
But consider a function which equals a "contains" function of a list in C#:
public static bool Contains(int num, List<int> list) {
foreach (int i in list) {
if (i == num) return true;
}
return false;
}
If you would translate that one by one, the compiler will tell you there is missing an else branch and I do unterstand why:
let Contains (num : int) list =
for i in list do
if i = x then true //Won't compile due to a missing else branch!
false
Instead, you'd probably write a recursive function like that:
let rec Contains (num : int) list =
match list with
| [] -> false
| head::tail -> head = num || (Contains num tail)
And I'm be fine with that, but in some situations, it is hard to do pattern matching. Is there really no way to do the described above? Couldn't one use a keyword like yield (or something similar to "return" in C#)?
An early return
in C# is really just a GOTO. And I would consider that bad style, except for the "bouncer pattern" (validation). The argument there usually is to get rid of mental overload as early as possible. Given F#'s expressiveness, most validation can happen through types, so the otherwise ubiquitous if param = null || invalid(param) return
style is not (or at least less) needed. Once you embrace the functional style, you'll find that there is less and less need for it. If needed, you can always simulate the goto :-)
exception Ret of string
let needsEarlyReturn foos =
try
for f in foos do
if f > 42 then Ret "don't do" |> raise
// more code
if f > 7 then Ret "that ever" |> raise
"!"
with Ret v -> v