我真的很喜欢 Jeffrey 的回答,但如果您想了解更多详细信息以及了解let () = foo 的含义,这里是一些课外阅读。
抽象地说,OCaml 程序的操作可以定义为一种机器,它可以简化表达式,直到它们变得不可约。一个不可约的表达式被称为一个值。例如,5 + 3 减少到 8 并且没有其他方法可以减少 8 所以 8 是一个值。一个更复杂的值示例是(fun x -> x + 1)。一个更复杂的表达示例是
(fun x -> x + 1) 5
简化为6。
语言的整个语义被定义为一组这样的归约规则。 OCaml 中的程序是表单定义的有序列表,
let <pattern> = <expression>
因此,当 OCaml 程序被评估(执行)时,它会减少每个定义的部分并将其分配给左侧的模式,例如,
let 5 = 2 + 3
是 OCaml 中的有效定义。它将2 + 3 表达式简化为5,然后尝试将结果值与左侧匹配。如果匹配,则评估下一个定义,依此类推。如果不是,则程序终止。
这里的5 是一个非常简单的值,它只与5 匹配,一般来说,您的值会更复杂。但是,有一个比5 更原始的值。这是一个unit 类型的值,它只有一个居民,表示为()。这也是减少带有副作用的口语表达的价值。由于在 OCaml 中每个表达式都必须归约为一个值,因此我们需要一个不代表任何值的值,即单位。例如,print_endline "foo" 减少为 (),其副作用是将字符串 foo 发送到标准输出。
因此,当我们写
let foo () = print_endline "foo"
let () = foo ()
我们评估(减少)函数foo,直到它达到() 值,这表明我们完全减少了foo ()。
我们也可以使用通配符匹配器并写
let _ = foo ()
或将结果绑定到变量,例如,
let bar = foo ()
但是在表达式的左侧使用() 被认为是一种很好的样式,该表达式的计算结果为(),以表明右侧不会产生任何有趣的值。它还可以防止常见错误,例如,
let () = foo
会产生一个错误,指出unit -> unit 不能与unit 匹配,甚至提供提示:Did you forget to provide ()' 作为参数?`