Break a statement (expression) into multiple lines: how to indent

Tag: f# , indentation Author: chen515159 Date: 2011-04-08

I found it's very hard to search for the simple indentation guide in F#. Basically, I am wondering what's the rule for multiple-line statement indentation. In C#, there is no problem because whitespace doesn't count. Although I can write F# code according to my intuition and it works, I really want to know what's the rule for breaking one statement into multiple lines. I write as

printfn "%d"
    1

It works as expected

And if I write them in the same column, something goes wrong.

>
printfn "%A%A"
1
[];;
> //nothing is returned... and no error in this case

I want to confirm the basic rule for doing this. It's a little annoying when you can't be sure what you are doing.

Thanks in advance

I just tried another case

List.iter
    (printfn "%d")
        [1..10];;

And it prints out 1 to 10. Why it's not

List.iter
    ((printfn "%d")
        [1..10]);;

Best Answer

As Yin points out, the rule is that arguments of a function should be indented further than the call to the function. To add more details, your first snippet is interpreted like this:

printfn "%A%A";
1;
[];

Each of these is a valid expression that returns something (function, number, empty list) and then ignores the result and continues. Because they are written in the top-level scope, F# Interactive doesn't emit a warning that you're ignoring some values. If they were in a do block or let declaration:

do
  printfn "%A%A"
  1
  []

The F# compiler would emit a warning when sequencing expressions (using ;) that do not return unit:

stdin(5,3): warning FS0193: This expression is a function value, i.e. is missing arguments. Its type is 'a -> 'b -> unit.

stdin(6,3): warning FS0020: This expression should have type 'unit', but has typ e 'int'. Use 'ignore' to discard the result of the expression, or 'let' to bind the result to a name.

stdin(5,3): warning FS0020: This expression should have type 'unit', but has typ e ''a list'. Use 'ignore' to discard the result of the expression, or 'let' to b ind the result to a name.

comments:

But in the previous case, it should return val it: 'a -> 'b -> unit, val it: int = 1, val it: 'a list = []

Other Answer1

In your second example, you should indent:

>
printfn "%A%A"
  1
  [];;

Otherwise the three expressions are three sequential expressions, not a single expression.

You can refer F# Language Specification for firm rules, e.g. Chapter 15 in the specification.

comments:

I couldn't find the specific rule for breaking a single statement. Maybe I can read it more carefully when I have time. But I don't think it's inside the specification.