views:

213

answers:

1

I'm learning F#. I started by looking over the F# samples from Microsoft.

I ran across this statement:

let line1,line2 = 
    use sr = System.IO.File.OpenText @"test.txt"
    let line1 = sr.ReadLine() 
    let line2 = sr.ReadLine() 
    (line1,line2)

Can anyone explain this statement to me?

What type is being defined here? A function? A tuple?

Why do line1 and line2 have to be redefined within the definition of line1,line2 (let line1 = ... let line2 =)?

What's with the final line, (line1, line2) and how does this tie into the type of the original definition? Is this the function return?

Is "statement" even the right word to use for a definition in F#?

Thanks.

+10  A: 

The general form for binding identifier values in F# is

let pattern = expression

In this case, the pattern is "line1, line2", which is a tuple pattern, it will expect to bind to a 2-tuple of values and assign the names "line1" and "line2" to those two values.

The expression is the next 4 lines. Inside that expression there are local variables. They happen to also be named "line1" and "line2", but they could easily have been renamed "x" and "y" or whatever - the scope of those identifiers is local to this indented expression. (The fact that the same names are used as the names in the outer scope has no effect as far as the compiler is concerned.)

The final line if the expression is the 'return value' of the expression. In this case it returns the 2-tuple of values "line1" and "line2" (or "x" and "y" if you rename them for clarity of exposition). Incidentally, since these two values each have type "string", the type of the return expression is "string*string", which is a 2-tuple where each value is a string. This means the original "line1" and "line2" names on the first line will each be inferred to have type "string".

F# is functional, and so in a sense "everything is an expression" and "there are no statements" (only sequences of expressions that are sequentially evaluated), but it is ok IMO to (ab)use the term "statement" to describe the inner "let" lines, unless you're trying to be very precise.

Brian
Great explanation! But how would you use this pattern in the calling code? Could you just as easily have named it something else, such as[code]let getStringTuple = ...[/code]?
MEMark
Yes (try it and see)
Brian