“let () =” 的意思是什么?

huangapple go评论51阅读模式
英文:

How to make sense of "let () ="

问题

在OCaml中,如何理解这样的定义:

let () = print_endline "hello world"

OCaml中的Let-definitions应该像这样:let x = e,但上面的()不是一个变量。那么这里会发生什么?

我认为更合理的写法应该是:

let _:unit = print_endline "hello world"
英文:

In OCaml, how to make sense of a definition like:

let () = print_endline "hello world"

Let-definitions in ocaml should look like let x = e but above () is not a variable. So what happens there?

I think it would make more sense to write:

let _:unit = print_endline "hello world"

答案1

得分: 3

"let"绑定的语法是“pattern = expression”。最常见的模式是变量名、通配符或这些的元组模式,但只要模式与表达式具有相同的类型,任何种类的模式都是有效的。

语义是表达式将与模式匹配,如果匹配成功,模式绑定的变量(如果有的话)将在let的作用域中绑定。如果匹配失败,将会抛出异常。

因此,对于let () = something,你有一个不绑定任何变量且永远不会失败的模式(因为unit类型的表达式永远不会产生除()之外的值)。所以这确实与let _:unit = ...在功能上等效,只是更加紧凑。

英文:

The syntax for let bindings is "pattern = expression`. Most often the pattern will be a variable name, a wildcard or a tuple pattern of those, but every kind of pattern is valid (as long as the pattern has the same type as the expression).

The semantics are that the expression will be matched against the pattern and if the match succeeds, the variables bound by the pattern (if any) will be bound during the let's scope. If it fails, there will be an exception.

So for let () = something, you have a pattern that binds no variables and can never fail (since an expression of type unit can never produce a value other than ()). So this is indeed functionally equivalent let _:unit = ..., just a bit more compact.

答案2

得分: 2

A let-definition in OCaml can define many values at the same time. For instance, with

let (x,y) = 1, 2 in x + y

we are defining both x and y with the same let.

This works the same as using patterns to bind part of an argument in a function definition

let f (x,_,y) = x + y

(One may note that we can rewrite the let-definition above to use only this second form as

(fun (x,y) -> x + y) (1,2)

)

Moreover, this construction works for all patterns. For instance, we can apply it to pick three variables from nested fields of a record

type x = { x: int; y: int }
type a = { a: x; b:int; c:x }
let { a={ x; _ } ; b; c = {y; _ } } = { a = {x=0;y=1}; b=2; c={x=3;y=4} }

Note that in all illustrations above, we were only using product types. The reason here is that exhaustive patterns are a bit more exotic for variants, but they are still possible. For instance

type t = A of int | B of int * int * float
let (A x|B(_,x,_)) = A 0

binds x to 0.

Consequently, a definition of the form

let () = print_endline "hello world"

can be seen as a definition where 0 values are bound by the pattern and as the symmetric of

(fun () -> print_endline "hello world")
英文:

A let-definition in OCaml can define many values at the same time. For instance, with

let (x,y) = 1, 2 in x + y

we are defining both x and y with the same let.
This works the same as using patterns to bind part of an argument in a function definition

let f (x,_,y) = x + y

(One may note that we can rewrite the let-definition above to use only this second form as

(fun (x,y) -> x + y) (1,2)

)

Moreover, this construction works for all patterns. For instance, we can apply it to pick three variables from nested fields of a record

type x = { x: int; y: int }
type a = { a: x; b:int; c:x }
let { a={ x; _ } ; b; c = {y; _ } } = { a = {x=0;y=1}; b=2; c={x=3;y=4} }

Note that in all illustration above, we were only using product types. The reason here is that exhaustive patterns are bit more exotic for variants, but they are still possible. For instance

type t = A of int | B of int * int * float
let (A x|B(_,x,_)) = A 0

binds x to 0.

Consequently, a definition of the form

let () = print_endline "hello world"

can be seen as a definition where 0 values are bound by the pattern and as the symmetric of

(fun () -> print_endline "hello world")

答案3

得分: 1

以下是翻译好的部分:

模式匹配的语法与构造函数的语法相匹配。
通常,一个类型可以有多个构造函数:

type colour = Red | Blue | Green

但是,让我们只有一个唯一的构造函数:

type colour = Red

然后Red既是构造函数,也是类型colour的模式匹配表达式。在这里,我定义一个不断返回Red的函数:

let f () = Red

在这里,我也可以进行匹配,前提是匹配是穷尽的:

let Red = f()

对于unit类型的唯一构造函数也是如此,它写作(),原因如下。

上面的示例有点人为,但如果你将数据附加到构造函数,它会更有用:

type colour = Red of float

然后,你可以创建一个红色的阴影如下:

let foreground = Red 0.8

并在let中使用模式匹配器:

# let darker (Red v) = Red (v *. 0.9)
val darker : colour -> colour = <fun>

例如:

# darker foreground;;
- : colour = Red 0.720000000000000084
英文:

The syntax for pattern matching matches the syntax for constructors.
Typically a type can have multiple constructors:

 type colour = Red | Blue | Greed

But let's have a unique constructor instead:

 type colour = Red

Then Red is both a constructor and a pattern matching expression for type colour. Here I define a function that constantly returns Red:

let f () = Red

And here I can match it too, given that the match is exhaustive:

let Red = f()

This is not different for the unique constructor of the unit type, which is written () for reasons.

The example above is a bit artificial but if you attach data to the constructor then it is more useful:

type colour = Red of float

Then you can create a shade of red as follows:

let foreground = Red 0.8

And use the pattern matcher in let:

# let darker (Red v) = Red (v *. 0.9)
val darker : colour -&gt; colour = &lt;fun&gt;

For example:

# darker foreground;;
- : colour = Red 0.720000000000000084

huangapple
  • 本文由 发表于 2023年4月13日 16:24:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/76003254.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定