Inside F#

Brian's thoughts on F# and .NET

New F# users: some tips to help you become productive more quickly

Posted by Brian on May 3, 2008

(Quick note: we just had a new release – check it out!)

I have written a lot of blog entries about some of the coolest features and nicest aspects of programming with F#.  F# is pretty new to most people, though, and when learning a new programming language, there are bound to be some frustrating moments along the way as you learn the new syntax and reorganize some of your mental models for structuring code.  The F# team is always looking for ways to reduce the initial learning curve, so today I’ll mention a few issues that new users commonly encounter, and I’ll describe some useful things to know "up front" that will make it easier to ramp up on F#. 

So without further ado, here are a handful of tips that will make it easier for you to hit the ground running with F#.

The "tab" character is illegal in #light code

Almost all the F# code in the world you will find uses the lightweight syntax option – using the "#light" directive at the top of the file (which will probably become the default in a future release).  When using #light, layout matters (whitespace is significant), and the "tab" character is illegal.  Thus many users exploring F# in Visual Studio for the first time will try to define their first function, press ‘tab’ to indent the body, and all of a sudden there are error squiggles highlighting the whitespace just typed.  Yikes!  (EDIT: (Jan 2010) #light is now the default; you can quit putting #light at the top of your files.)

Fortunately, the solution is simple: in Visual Studio, go to "Tools\Options\Text Editor\F#\Tabs" and select "Insert spaces".  Do this once, and you’re forever good to go.  Others have blogged about this before, check the link for a screenshot.  (If you’re using an editor other than Visual Studio, make the corresponding change to convert tabs to spaces when editing F# source files in your editor-of-choice.)  (EDIT: (Jan 2010) Whether you have the CTP or VS2010, the defaults are now set up properly, you do not have to customize anything here to make it work.)

There is a distinction between tupled functions versus curried functions

People new to F# need to learn about the two different ways that functions can be called.  I have talked about the difference between using tuples and using currying before.  Consider:

    // fc : int -> int -> int
    let fc x y   = x + y    // curried
    // ft : int * int -> int
    let ft(x, y) = x + y    // tupled

Since functions can be written in both styles, it’s important to call each function with the right syntax, e.g.:

    fc 3 4
    ft(3,4)

If you mix a curried function with a tupled call site, or vice-versa, you’ll end up with an error message like one of these:

    fc(3,4)  // This expression has type ‘a * ‘b but is here used with type int
    ft 3 4   // This value is not a function and cannot be applied

Though you don’t have to understand terms like "currying", "partial application", and "higher-order functions" to get started using F#, you do at least have to be aware of the curried-versus-tupled distinction in order to author programs that will typecheck.  Tupled functions have types where arguments are separated by "*", and they are defined and called with tuple syntax (parentheses and commas).  Curried functions have types where arguments are separated by "->", and they are defined and called using just whitespace to separate the arguments.  You must learn this distinction in order to survive your first week of programming in F#.  The good news is, if you’ve read this far in today’s blog, you already know enough that you’re likely to never again get blocked by the "curried/tupled" distinction.

Don’t panic about various syntax errors for simple code

Another common experience for people writing F# code for the first time is getting tripped up by the interactive feedback Visual Studio provides while you are typing.  Suppose you intend to write a simple function like this:

    let circumference r =
        let pi = 3.14
        let d = 2.0 * r
        pi * d

That’s perfectly legal F# code.  However, while you are typing, you’ll get to points like

    let circumference r = 
        let pi = 3.14 
        let d = 2.0 * r
        // cursor here, haven’t finished typing yet

where you haven’t finished typing yet, and you might get surprised and hung up by error squiggles under the last "let" with messages like "syntax error" or "error in the return expression for this ‘let’".  What’s going on here?

The lightweight syntax option makes it easy to forget that these "let"s inside the body of the function are not statements, rather they are the beginning of an expression.  (F#, like most functional languages, emphasizes expressions rather than statements.)  The F# grammar rule for a let expression looks something like "let ident = expr in body-expr".  The key part is the "in body-expr" at the end.  A let expression must have a body!  Since the lightweight syntax allows us to omit the "in", the necessity of a body is especially easy to forget.  If I make the original code very, very explicit:

    let circumference r =
        begin  // don’t write code like this; just emphasizing how it parses
            let pi = 3.14 in
                begin
                    let d = 2.0 * r in
                        begin
                            pi * d
                        end
                end
        end

then the error makes more sense when you realize that, in the original function, if you haven’t typed the last line of code yet, it’s equivalent to

    let circumference r =
        begin  // don’t write code like this; just emphasizing how it parses
            let pi = 3.14 in
                begin
                    let d = 2.0 * r in
                        // cursor here, haven’t finished typing yet
                end
        end

Now the error message "error in the return expression for this let" (pointing at the "let" in "let d=…") makes more sense – the let expression at the cursor has no body! 

The solution here is just to be aware of this aspect of the language and how it interacts with the tooling.  The F# language service in Visual Studio does more "online" parsing, typechecking, and semantic analysis than C#.  Whereas in C# you typically need to explicitly "build" in order to get typechecking errors, in F#, the language service continually running in the background is re-parsing and typechecking as you type, so as to provide interactive feedback (which is especially useful for type-inference).  However as a consequence of this, some of the error reporting and squiggles are a little "over-eager" when it comes to code you’re still in the middle of editing.  Though we’ll continue to improve the F# interactive editing experience inside Visual Studio, it is important to be aware of this aspect and not let it throw you for a loop.  (On a related note, we also have a bit of work ahead of us to improve the quality of the compiler error diagnostics.  A "syntax error" may tell you where the problem is, but it does not help you get un-stuck if you don’t know the correct syntax!)

Summary

I’ve discussed a few simple issues that nearly every new F# programmer faces during their first week using the language.  Each issue is simple to get past, once and for all – provided you have the right little bit of understanding or tooling!  Don’t let little issues like these prevent you from learning, using, and enjoying the language.  If you find yourself getting stuck, let us know – the F# team would love to hear your feedback – both positive and negative.  What aspects of F# do you enjoy most?  Are there parts you find confusing or frustrating?  Do you have feedback about the F# language, libraries, tooling, or setup?  Just send us mail telling us about your experience!

The best time to send feedback is now!  F# is a real language you can use today, so go download the latest release and try it out!  As we transition from releasing F# out of Microsoft Research to releasing F# out of Microsoft Developer Division (another milestone on the long drive towards making F# a first-class language on the .NET platform), we’ll be tying down the remaining loose ends and driving the core language and libraries to stabilization.  Which is why now is the best time for user feedback; the suggestions you provide today could have a marked impact on the experience found on thousands of developer desktops just a few years down the road.  Let us know what you think of F#!

Advertisements

4 Responses to “New F# users: some tips to help you become productive more quickly”

  1. Joe said

    This is really a question not a comment.  First let me say that I\’m a DBA not a programmer by trade.  I\’m new to both F# and Visual Studio 2008.  So please forgive my ignorance if what I\’m asking could be construed as "Brain Dead."  Anyway, I set the tab option to insert spaces as described in this article but when use the tab key I get a long list of options scroll across my F# Interactive workspace within VS08 and the 4 spaces are not inserted.  Has anyone else experienced this behavior and solved it.

  2. Brian said

    The \’tab\’ bit I wrote about is for typing inside the Visual Studio editor window (where you edit a .fs file).
     
    If you are in FSI (the F# interactive window), then \’tab\’ is the \’intellisense\’ character that shows all possible completions of the currently prefixed word.  This is apparently true even if you haven\’t started typing a word (e.g. you are at the beginning of the line), in which case every possible legal completion is displayed.  Indeed, that behavior is not helpful.  I\’ll file a bug.  Ideally, I think in FSI, the \’tab\’ character should \’insert whitespace\’ if you are not currently in the middle of a word, and \’intellisense\’ if you are in the middle of a word.  Thanks for pointing this out!

  3. Matteo said

    Brian,
    This suggestions/issue is currently tracked in our database by item #2154.

  4. Spurry said

    Someone has to ask… ;-) What is the point of making the \’Tab\’ character illegal?Why not just treat it as a space or something when parsing it, and avoid all the inevitable confusion?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: