functions in F# .. why is it not compiling

2019-09-06 08:08发布

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"

标签: f#
3条回答
老娘就宠你
2楼-- · 2019-09-06 08:33

I think it is helpful to understand the non-light syntax here. Let's translate:

1st Version (let binding expressions)

let samplefn() =
    let z = 2 in
    let z = z * 2 in
    printfn "hi";;

samplefn();;

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:

let a = (let b = 3 in b + 2) //a is 5

2nd Version (top-level let bindings)

let z = 2;;
let z = z * 2;;
printfn "Error: Duplicate definition of value z";;

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 bind z twice within the same scope. Whereas using the expression form of let bindings in Example 1, we bind z anew for each sub-scope in the expression chain. Note that we could do something like this at the top-level:

let z = (let z = 2 in z * 2);;
查看更多
闹够了就滚
3楼-- · 2019-09-06 08:46

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 is printfn "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, the let z = z * 2 actually creates a new value called z and binds to it the value of the outer z times 2, then uses it in the body of the let (which is the printfn in this case). A nested let 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 redefine z in the same scope, which is an error. You can use parentheses to tell the compiler how to properly interpret the last example:

let z = 2
(let z = z * 2
printfn "z = %d" z)
printfn "z = %d" z

The above will print

z = 4
z = 2

查看更多
Bombasti
4楼-- · 2019-09-06 08:52

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:

let samplefn() =
    let z = 2
    let z = z * 2
    ()

which defines a function that does absolutely nothing (returns unit). Perhaps a better example is this:

let samplefn() =
    let z = 2
    let z = z * 2
    z

which will return 4 (the value of the binding for label z).

查看更多
登录 后发表回答