F# basic function definition syntax

In the comments to this post, Anon and Josh complain about the syntax of F#. On one hand, they've got a point: most programmers are used to notations similar to those of Visual Basic, C# or Java, and for them many of the syntactic details of F# will look weird (or just plainly annoying ;-) ). On the other hand, it's not the case -as Josh suggests- that Microsoft is creating a new language with a purposedly cryptic syntax :-D; actually, F# was designed to follow as much as possible the syntax -and semantics- of OCaml (1996), a popular language in the functional world. OCaml in turn basically offers object-oriented extensions to Caml (1985), which inherits most of its syntax -and semantics- from ML (circa 1973). So, as much as I would like to say that Microsoft has created a whole new language, its more like it is moving the spotlight to a tradition as old (LISP anyone?) as imperative languages themselves, by providing an implementation nicely integrated into .NET Framework.

But, history and traditions apart, as Anon says, F# could look like greek to someone fluent in C#, so I'll try to give you one or two tips on the basic fsharpian vocabulary:

F# function definition basic syntax

In line 2, you can see how you define a function in F#, a few points worth mentioning:

  1. You don't need parenthesis to surround the parameters
  2. You don't use commas to separate parameters, a simple blank space will do (and beware that the comma is used to denote a totally different thing: a tuple, but let's not get ahead of ourselves).
  3. To separate the "head" (my term) of the function from its "body" you put an equal sign
  4. To the right of the equal sign you put the expression that is evaluated every time you call the function (just one expression, mind you, although it can perfectly grow to fill several lines, and it usually does)
  5. There are no methods or procedures in F#, just functions, everything you call must return something
  6. The function definition ends when:
    1. The line finishes, as in my example in line 2
    2. If we are using the so called "light" syntax (which will be so most of the time), the body indents one or more spaces to the right of the let keyword, in this case the function finishes when the indentation finishes, as in the other 3 examples of the figure above
  7. One curious thing is the fact that, most of the time, you don't need to declare the type of the parameters or the result, but beware:
    1. F# is a totally strongly typed language (like C# or Java) so everything has a type
    2. What's going on is that F# has a powerful type inference mechanism, so the compiler (yes, F# is compiled not interpreted) deducts the type of the parameters and the results from the operations you do with them. For example, when you do oper1 * oper2, you already know that oper1 and oper2 must be numbers. This works like a charm and trasparently in most scenarios, but sometimes you have to give a hand to the compiler by writing down the types explicitly, but again let's live that for (very) later

All in all, if you think about it, F# syntax is simpler than that of C#, what with:

let addSquares a b = a * a + b * b

Instead of:

int AddSquares(int a, int b) { return a * a + b * b; }

So in the end we have a very clean result, but, whew, now that I tried to explain it, may be Josh has got a point indeed: there's a lot to be said about F# syntax, so I'll live the explanation of the dreaded match expression for other night ;-). Furthermore, you'll have to trust me: after a few nights toying with the language you'll become comfortable with the syntax.

One last interesting point to note is that, syntax aside, the real power of languages like F# lays in its semantics and power of expression, that's why a sizable portion of that power has been implemented in C# 3.0 and VB 9 (LINQ being its more visible offspring) so, even if you run from the F# syntax, you won't be able to hide from its semantics... ;-)

8 Comments

  • You forgot the reeeeeeally inefficient (but syntactically cool) way to implement isOdd...

    let isOddSlow 0 = false
    | isOddSlow n = ! isOddSlow (n - 1)

    (It's been a while since I did anything in ML and I was never entirely clear on the exact difference in semantics between "let" and "fun" so please correct my syntax as appropriate)

  • Well, Stuart, I think you're going to need a veeeeery long stack to get away with isOddSlow (especially if they give you a negative number ;-) ). As for the differences between let and fun, I'll better point you to the experts now: http://www.strangelights.com/FSharp/Wiki/Default.aspx, as I'll try to keep to more terrestrial things for the moment here (or somebody will come back and hit me in the hands again...)

  • The definition of isItOddSimpler is unnecessarily redundant. It could be let isItOddSimpler number = number%2 = 0 . This is a common pitfall.

  • Hi d2bg,

    This time, I knew about it, but I was trying to be as simple as possible in the examples, I preferred not to mention your very compact (and, to me, elegant) version because it shows to different uses for the "=" sign: labeling a value and comparison, because this is the kind of ambiguities that confuse beginners.

  • Since we're nitpicking syntax here...although #4 and #5 are true in the sense that everything in F# is an expression (one of the marks of functional programming paradigm), one of the possible types is "unit", meaning nothing returned. And while Stuart's example may be valid ML (I just don't know), in F# a short lambda that does nothing but pattern match uses the "function" keyword. I also like to point out that function definition syntax matches function invocation syntax: no parantheses are used there, either. (OK, you do use parantheses for calling methods in general .Net libraries, but that's for interoperability reasons.)

  • I was wondering about having
    number % 2 = 0 return that the number is an odd number?

  • Hey rlf,

    Thank you for pointing out such a silly error of me, I got my odd condition wrong, argh! Of course an even simpler way of expressing that function would be:

    let isItOddSimplerer number = number % 2 = 1

    :-)

  • Wonderful post. I learned many interesting things. Thank you)

Comments have been disabled for this content.