I have written two versions of code. The first one works as expected and print "Hi". the second one gives me error that "block following this let is unfinished"
1st version
#light
let samplefn() =
let z = 2
let z = z * 2
printfn "hi"
samplefn()
2nd version
#light
let samplefn() =
let z = 2
let z = z * 2
samplefn()
Only difference is the printfn is absent in the second version. I am using Visual Studio 2010 as my IDE. I am very new to F# but this error seems very strange to me. I guess I am missing some very important concept. Please explain.
Edit: Also if I do it outside the function I get error even with the first version of code.
#light
let z = 2
let z = z * 2
printfn "Error: Duplicate definition of value z"
I think it is helpful to understand the non-light syntax here. Let's translate:
1st Version (let binding expressions)
The important thing to understand here is that all non-top-level let bindings are actually expressions of the form
let <variable> = <expression1> in <expression2>
where<variable>
is bound to the result of<expression1>
in a new scope<expression2>
, and<expression2>
is the return value of the entire expression. The light syntax makes you believe such let bindings are variable assignments / statements, when in fact it really is true that almost everything in F# is an expression.Perhaps the following illustrates this more clearly:
2nd Version (top-level let bindings)
Top level let-bindings are terminated with
;;
, indicating the completion of what may be thought of as a statement. The top-level is a single scope, and here we get an error for trying to bindz
twice within the same scope. Whereas using the expression form of let bindings in Example 1, we bindz
anew for each sub-scope in the expression chain. Note that we could do something like this at the top-level:A
let
that is not at the top level (e.g. your indented ones) has to have a statement (actually an expression, as pst notes) called a "body" following the assignment. In the first example the body isprintfn "hi"
, while the second example has no body. That's what the compiler is complaining about.Note that in your function definitions the inner
let
expressions actually create nested scopes. That is, thelet z = z * 2
actually creates a new value calledz
and binds to it the value of the outerz
times 2, then uses it in the body of thelet
(which is theprintfn
in this case). A nestedlet
will always have a body. It is the nesting which allows the seemingly duplicate definition.Since an outermost
let
does not need a body, the compiler thinks you're trying to redefinez
in the same scope, which is an error. You can use parentheses to tell the compiler how to properly interpret the last example:The above will print
let
binds a value to a label but otherwise doesn't do much else. Your function contains two bindings but doesn't use them, and so you get an error.To think of it another way, all functions in F# need a return value, which is the value of the last executed expression in your function.
let
doesn't have a return value so your function is invalid. To fix this you can add a return value, for example:which defines a function that does absolutely nothing (returns
unit
). Perhaps a better example is this:which will return 4 (the value of the binding for label
z
).