Brian's profileInside F#BlogGuestbookNetwork Tools Help

Blog


    May 03

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

    (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!

    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.)

    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#!

    Comments (4)

    Please wait...
    Sorry, the comment you entered is too long. Please shorten it.
    You didn't enter anything. Please try again.
    Sorry, we can't add your comment right now. Please try again later.
    To add a comment, you need permission from your parent. Ask for permission
    Your parent has turned off comments.
    Sorry, we can't delete your comment right now. Please try again later.
    You've exceeded the maximum number of comments that can be left in one day. Please try again in 24 hours.
    Your account has had the ability to leave comments disabled because our systems indicate that you may be spamming other users. If you believe that your account has been disabled in error please contact Windows Live support.
    Complete the security check below to finish leaving your comment.
    The characters you type in the security check must match the characters in the picture or audio.

    To add a comment, sign in with your Windows Live ID (if you use Hotmail, Messenger, or Xbox LIVE, you have a Windows Live ID). Sign in


    Don't have a Windows Live ID? Sign up

    Spurrywrote:
    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?
    July 10
    Matteowrote:
    Brian,
    This suggestions/issue is currently tracked in our database by item #2154.
    May 15
    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!
    May 14
    Joe Moylewrote:
    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.
    May 13

    Trackbacks

    Weblogs that reference this entry
    • None