F#中的函数。。为什么它没有编译

F#中的函数。。为什么它没有编译,f#,F#,我已经编写了两个版本的代码。第一个按预期工作并打印“Hi”。第二个给了我一个错误“这个let后面的块未完成” 第一版 #light let samplefn() = let z = 2 let z = z * 2 printfn "hi" samplefn() 第二版 #light let samplefn() = let z = 2 let z = z * 2

我已经编写了两个版本的代码。第一个按预期工作并打印“Hi”。第二个给了我一个错误“这个let后面的块未完成”

第一版

#light 

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

samplefn()
第二版

#light 

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

samplefn()
唯一的区别是第二版中没有printfn。我正在使用VisualStudio2010作为我的IDE。我对F#很陌生,但这个错误对我来说似乎很奇怪。我想我遗漏了一些非常重要的概念。请解释一下

编辑:如果我在函数外执行此操作,即使是在代码的第一个版本中,也会出现错误

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

不在顶层的
let
必须在赋值后有一个称为“body”的语句(实际上是一个表达式,如pst所述)。在第一个示例中,主体是
printfn“hi”
,而第二个示例没有主体。这就是编译器所抱怨的

请注意,在函数定义中,内部
表达式实际创建嵌套作用域。也就是说,
let z=z*2
实际上创建了一个名为
z
的新值,并将外部
z
乘以2的值绑定到它,然后在
let
的主体中使用它(在本例中是
printfn
)。嵌套的
let
将始终具有主体。嵌套允许看似重复的定义

由于最外层的
let
不需要主体,编译器认为您试图在同一范围内重新定义
z
,这是一个错误。可以使用括号告诉编译器如何正确解释最后一个示例:

let z = 2
(let z = z * 2
printfn "z = %d" z)
printfn "z = %d" z
上面将打印z=4 z = 4 z = 2
z=2

将一个值绑定到标签上,但除此之外,没有其他作用。您的函数包含两个绑定,但未使用它们,因此会出现错误

换句话说,F#中的所有函数都需要一个返回值,即函数中最后执行的表达式的值
let
没有返回值,因此函数无效。要解决此问题,可以添加返回值,例如:

let samplefn() =
    let z = 2
    let z = z * 2
    ()
它定义了一个完全不执行任何操作的函数(返回
unit
)。也许更好的例子是:

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

它将返回4(标签
z
的绑定值)。

我认为理解这里的非light语法很有帮助。让我们翻译一下:

第1版(let绑定表达式) 这里需要了解的重要一点是,所有非顶级let绑定实际上都是
let=in
形式的表达式,其中
绑定到新范围
中的
结果,并且
是整个表达式的返回值。light语法让您相信这样的let绑定是变量赋值/语句,而事实上F#中几乎所有内容都是表达式

也许以下内容更清楚地说明了这一点:

let a = (let b = 3 in b + 2) //a is 5
第二版(顶级let绑定) 顶级let绑定以
;;终止,表示可能被认为是语句的完成。顶层是一个单一的作用域,这里我们得到一个错误,因为我们试图在同一个作用域内绑定两次
z
。而在示例1中使用let绑定的表达式形式,我们为表达式链中的每个子作用域重新绑定
z
。请注意,我们可以在顶层执行以下操作:

let z = (let z = 2 in z * 2);;

谢谢我已编辑了我的问题,使其具有另一个条件。你能解释一下吗?“经过一段时间后,你必须有一个表达”——我想这并不总是正确的。因为我可以只编译#light let x=42,所以我编辑了我的答案以解释您的编辑。
let z = 2;;
let z = z * 2;;
printfn "Error: Duplicate definition of value z";;
let z = (let z = 2 in z * 2);;