let+、let*和let()之间的区别是什么?

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

Difference between let+, let* and let()?

问题

由于OCaml的文档有限,我会很感激如果有人能够解释不同用法的let之间的区别。

我尝试查看https://dev.realworldocaml.org/toc.html,但网站没有简便的搜索方式。谷歌搜索引导我到一些文章,但没有得到确切的解释。

英文:

As the documentation on OCaml is sparse, i would appreciate if some one can explain the difference in different flavors of let usage.

I tried looking into https://dev.realworldocaml.org/toc.html, but there is no easy way to search in the website. Google search landed me to some articles, but did not get the exact explanation.

答案1

得分: 5

let表达式的基本形式是:

let p1 = e1
and p2 = e2
...
and pN = eN
in e

其中N至少为1。在这种形式下,let表达式模式匹配通过对LHS模式对RHS表达式进行评估而产生的值,然后使用LHS模式定义的新绑定在范围内评估主体。例如,

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

评估结果为3。

let附有操作符名称时,它是所谓的“let操作符”或“绑定操作符”的应用(以便更容易搜索)。例如:

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

解糖为(let+) (1, 2) (fun (x, y) -> x + y)。(类似于将操作符+用括号括起来,使其成为(+),以引用其标识符,let操作符let+的标识符,就像它出现在let表达式中一样,将是(let+)。)

最后,当let绑定附有操作符名称时,所有的and绑定也必须附有操作符名称。

let* x = 1
and+ y = 2
and* z = 3 in
x + y + z

解糖为(let*) ((and+) 1 ((and*) 2 3)) (fun ((x, y), z) ->)

以下程序是无效的,并且没有意义,因为let绑定被用作操作符,但and绑定没有:

let* x = 1
and y = 2 in
x + y

这里介绍了绑定操作符,位于OCaml文档的“语言扩展”部分。

let () = e只是模式匹配的非操作符形式,其中()是匹配unit类型的唯一值的模式。unit类型通常是不会评估为有意义值的表达式的类型,但存在于副作用(例如print_endline "Hello world!")的情况下。匹配()可以确保表达式具有类型(),从而捕获部分应用错误。以下是类型检查的:

let f x y =
  print_endline x;
  print_endline y

let () =
  f "Hello" "World"

以下则不会:

let f x y =
  print_endline x;
  print_endline y

let () =
  f "Hello" (*缺少第二个参数,因此表达式的类型为string -> unit,而不是unit*)

请注意,绑定操作符对于方便使用“monad”和“applicative”非常有用,因此在学习绑定操作符时可能会听到这些词。但是,绑定操作符与这些概念本质上没有直接关联。它们只是解糖为我上面描述的表达式,任何其他意义(例如与monad的关系)都取决于操作符的定义方式。

英文:

The basic form of let expressions is:

let p1 = e1
and p2 = e2
...
and pN = eN
in e

where N is at least 1. In this form, let expressions pattern matches the value that results from evaluating the RHS expressions against the LHS patterns, then evaluates the body with the new bindings defined by the LHS patterns in scope. For example,

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

evaluates to 3.

When let has an operator name attached, it is the application of what is called a "let operator" or "binding operator" (to give you easier terms to search up). For example:

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

desugars to (let+) (1, 2) (fun (x, y) -> x + y). (Similar to how one surrounds the operator + in parentheses, making it (+), to refer to its identifier, the identifier for the let operator let+, as it appears in a let expression, would be (let+).)

Finally, when a let binding has an operator name attached, all the and bindings must have operator names attached as well.

let* x = 1
and+ y = 2
and* z = 3 in
x + y + z

desugars to (let*) ((and+) 1 ((and*) 2 3)) (fun ((x, y), z) ->).

The following program is invalid and has no meaning because the let binding is being used as an operator, but the and binding is not:

let* x = 1
and y = 2 in
x + y

Binding operators are covered in the "language extensions" section of the OCaml documentation.

let () = e is merely the non-operator form of a pattern match, where () is the pattern that matches the only value of the unit type. The unit type is conventionally the type of expressions that don't evaluate to a meaningful value, but exist for side effects (e.g. print_endline "Hello world!"). Matching against () ensures that the expression has type (), catching partial application errors. The following typechecks:

let f x y =
  print_endline x;
  print_endline y

let () =
  f "Hello" "World"

The following does not:

let f x y =
  print_endline x;
  print_endline y

let () =
  f "Hello" (* Missing second argument, so expression has type string -> unit, not unit *)

Note that the binding operators are useful for conveniently using "monads" and "applicatives," so you may hear these words when learning about binding operators. However, binding operators are not inherently related to these concepts. All they do is desugar to the expressions that I describe above, and any other significance (such as relation to monads) results from how the operator was defined.

答案2

得分: 4

考虑以下来自 OCaml 页面上关于 let operators 的代码:

let ( let* ) o f =
  match o with
  | None -> None
  | Some x -> f x

let return x = Some x

如果我们创建一个非常简单的映射:

module M = Map.Make (Int)

let m = M.(empty |> add 1 4 |> add 2 3 |> add 3 7)

如果我们想要编写一个函数,该函数接受一个映射和两个键,并添加这些键处的值,返回 int option,我们可以这样编写:

let add_values m k1 k2 =
  match M.find_opt k1 m with
  | None -> None
  | Some v1 ->
    match M.find_opt k2 m with
    | None -> None
    | Some v2 ->
      Some (v1 + v2)

当然,有多种定义这个函数的方式。我们可以这样做:

let add_values m k1 k2 =
  match (M.find_opt k1 m, M.find_opt k2 m) with
  | (None, _) | (_, None) -> None
  | (Some v1, Some v2) -> Some (v1 + v2)

或者利用异常的机会:

let add_values m k1 k2 =
  try 
    Some (M.find k1 m + M.find k2 m)
  with
  | Not_found -> None

Let operators 允许我们这样写:

let add_values m k1 k2 =
  let* v1 = M.find_opt k1 m in
  let* v2 = M.find_opt k2 m in
  return (v1 + v2)
英文:

Consider the following code from the OCaml page on let operators.

>
> let ( let* ) o f =
> match o with
> | None -> None
> | Some x -> f x
>
> let return x = Some x
>

If we create a very simply map:

module M = Map.Make (Int)

let m = M.(empty |> add 1 4 |> add 2 3 |> add 3 7)

If we wanted to write a function that takes a map and two keys and adds the values at those keys, returning int option, we might write:

let add_values m k1 k2 =
  match M.find_opt k1 m with
  | None -> None
  | Some v1 ->
    match M.find_opt k2 m with
    | None -> None
    | Some v2 ->
      Some (v1 + v2)

Now, of course there are multiple ways of defining this. We could:

let add_values m k1 k2 =
  match (M.find_opt k1 m, M.find_opt k2 m) with
  | (None, _) | (_, None) -> None
  | (Some v1, Some v2) -> Some (v1 + v2)

Or take advantage of exceptions:

let add_values m k1 k2 =
  try 
    Some (M.find k1 m + M.find k2 m)
  with
  | Not_found -> None

Let operators let us write:

let add_values m k1 k2 =
  let* v1 = M.find_opt k1 m in
  let* v2 = M.find_opt k2 m in
  return (v1 + v2)

huangapple
  • 本文由 发表于 2023年1月9日 07:38:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/75052061.html
匿名

发表评论

匿名网友

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

确定