英文:
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 -> colour = <fun>
For example:
# darker foreground;;
- : colour = Red 0.720000000000000084
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论