OCaml中function关键字和match with的区别
The difference of the function keyword and match with in OCaml
我正在学习OCaml,今天想到了这段代码。
let rec tree_to_list acc = function
| Leaf x -> x::acc
| Node (t1,t2) -> tree_to_list (tree_to_list acc t2) t1
据我了解,此功能与此功能相同
let rec tree_to_list2 acc t = match t with
| Leaf x -> x::acc
| Node (t1, t2) -> tree_to_list t1 (tree_to_list2 acc t2)
但是,我不明白第一个函数背后的语法。我发现关键字功能令人困惑。它应该只接受一个参数,例如:
function x -> x + 2
有人能帮我理解第一个函数的语法吗?如果有的话,两个函数的计算方式有什么不同。提前致谢。
第一个函数只是没有明确命名它的参数。
您可以对添加 2 的函数执行相同的操作:
let f = (+) 2;;
这将为任何数字加 2,并且 arg 未明确命名。
OCaml 中的函数是通过为参数提供模式来定义的。简单变量名的常见情况(如第一个函数中的 acc
)只是一种匹配所有值的特定模式。
因此,一种看待它的方法是 fun
定义了一个函数,其中包含任意数量的参数,每个参数都可以由一个模式给出。另一方面,function
定义了一个带有一个参数的函数,该参数可以由任意数量的模式给出。
# let dot = fun (a, b) (c, d) -> a *. c +. b *. d
val dot : float * float -> float * float -> float = <fun>
# let geti = function None -> 0 | Some i -> i;;
val geti : int option -> int = <fun>
fun
形式本质上可以吸收到 let
的左侧,以提供更简洁的符号。
即
let f = fun p1 p2 -> ...
可以写成
let f p1 p2 = ...
例如:
let dot (a, b) (c, d) = a *. c +. b *. d
你的第一个函数是使用两者的组合(一个简洁的fun
和右边的一个function
)。
As far as I understand this function does the same than this one
您是正确的,两个代码片段的计算结果相同。
Could someone please help me understand the syntax of the first function
由于@JeffreyScofield 似乎已经很好地回答了这部分,我将重点关注第二部分。
if any the difference in terms of how both functions are evaluated
tl;dr 没有区别,而且生成的组件实际上是相同的。我们将使用一个简单的斐波那契示例来展示使用 match with
和 function
符号发出的程序集。
let rec fib n = match n with
| 0 -> 0
| 1 -> 1
| i -> fib (i - 1) + fib (i - 2)
和
let rec fib = function
| 0 -> 0
| 1 -> 1
| i -> fib (i - 1) + fib (i - 2)
都生产
fib:
subq , %rsp
.L102:
cmpq , %rax
je .L100
cmpq , %rax
je .L101
movq %rax, 0(%rsp)
addq $-4, %rax
call fib
.L103:
movq %rax, 8(%rsp)
movq 0(%rsp), %rax
addq $-2, %rax
call fib
.L104:
movq 8(%rsp), %rbx
addq %rbx, %rax
decq %rax
addq , %rsp
ret
.L101:
movq , %rax
addq , %rsp
ret
.L100:
movq , %rax
addq , %rsp
ret
注意:我特意删除了 .align
等。
为了验证这些产生相同程序集的声明(因此被评估为相同),您可以简单地将每个函数放在一个文件中,然后 运行
$ ocamlopt -S fib-with-match.ml
$ ocamlopt -S fib-with-function.ml
当你diff
两者时,你应该看到它return没有区别:
$ diff fib-with-match.s fib-with-function.s
$
OCaml 中只包含 match
表达式的函数是很常见的,所以正如@JeffreyScofield 所说,function
有一个可用于模式匹配的参数。因此,它实际上是语法糖。
来源:
我在OCaml中解释函数定义的方式:
这些 等价于:
let name p1 p2 ... pn = expr
let name = function p1 -> function p2 -> ... -> function pn -> expr
let name = fun p1 p2 ... pn -> expr
如何背诵:
首先是语法糖,
第二个是它内部真正做的,
第三个是来自 caml 的遗产。
现在 function
只接受一个参数,但它经常像这样使用 - 这些是 等价的, 你在 p3 上匹配:
let f1 p1 p2 p3 = match p3 with
| [] -> expr
| ...
let f2 p1 p2 = function
| [] -> expr
| ...
您看到第二个版本保存了一些源字符,消除了视觉混乱。或者更多:没有必要在不使用 p3 变量的情况下将值绑定到 p3,因为模式匹配是最好的绑定结构。
我正在学习OCaml,今天想到了这段代码。
let rec tree_to_list acc = function
| Leaf x -> x::acc
| Node (t1,t2) -> tree_to_list (tree_to_list acc t2) t1
据我了解,此功能与此功能相同
let rec tree_to_list2 acc t = match t with
| Leaf x -> x::acc
| Node (t1, t2) -> tree_to_list t1 (tree_to_list2 acc t2)
但是,我不明白第一个函数背后的语法。我发现关键字功能令人困惑。它应该只接受一个参数,例如:
function x -> x + 2
有人能帮我理解第一个函数的语法吗?如果有的话,两个函数的计算方式有什么不同。提前致谢。
第一个函数只是没有明确命名它的参数。 您可以对添加 2 的函数执行相同的操作:
let f = (+) 2;;
这将为任何数字加 2,并且 arg 未明确命名。
OCaml 中的函数是通过为参数提供模式来定义的。简单变量名的常见情况(如第一个函数中的 acc
)只是一种匹配所有值的特定模式。
因此,一种看待它的方法是 fun
定义了一个函数,其中包含任意数量的参数,每个参数都可以由一个模式给出。另一方面,function
定义了一个带有一个参数的函数,该参数可以由任意数量的模式给出。
# let dot = fun (a, b) (c, d) -> a *. c +. b *. d
val dot : float * float -> float * float -> float = <fun>
# let geti = function None -> 0 | Some i -> i;;
val geti : int option -> int = <fun>
fun
形式本质上可以吸收到 let
的左侧,以提供更简洁的符号。
即
let f = fun p1 p2 -> ...
可以写成
let f p1 p2 = ...
例如:
let dot (a, b) (c, d) = a *. c +. b *. d
你的第一个函数是使用两者的组合(一个简洁的fun
和右边的一个function
)。
As far as I understand this function does the same than this one
您是正确的,两个代码片段的计算结果相同。
Could someone please help me understand the syntax of the first function
由于@JeffreyScofield 似乎已经很好地回答了这部分,我将重点关注第二部分。
if any the difference in terms of how both functions are evaluated
tl;dr 没有区别,而且生成的组件实际上是相同的。我们将使用一个简单的斐波那契示例来展示使用 match with
和 function
符号发出的程序集。
let rec fib n = match n with
| 0 -> 0
| 1 -> 1
| i -> fib (i - 1) + fib (i - 2)
和
let rec fib = function
| 0 -> 0
| 1 -> 1
| i -> fib (i - 1) + fib (i - 2)
都生产
fib:
subq , %rsp
.L102:
cmpq , %rax
je .L100
cmpq , %rax
je .L101
movq %rax, 0(%rsp)
addq $-4, %rax
call fib
.L103:
movq %rax, 8(%rsp)
movq 0(%rsp), %rax
addq $-2, %rax
call fib
.L104:
movq 8(%rsp), %rbx
addq %rbx, %rax
decq %rax
addq , %rsp
ret
.L101:
movq , %rax
addq , %rsp
ret
.L100:
movq , %rax
addq , %rsp
ret
注意:我特意删除了 .align
等。
为了验证这些产生相同程序集的声明(因此被评估为相同),您可以简单地将每个函数放在一个文件中,然后 运行
$ ocamlopt -S fib-with-match.ml
$ ocamlopt -S fib-with-function.ml
当你diff
两者时,你应该看到它return没有区别:
$ diff fib-with-match.s fib-with-function.s
$
OCaml 中只包含 match
表达式的函数是很常见的,所以正如@JeffreyScofield 所说,function
有一个可用于模式匹配的参数。因此,它实际上是语法糖。
来源:
我在OCaml中解释函数定义的方式:
这些 等价于:
let name p1 p2 ... pn = expr
let name = function p1 -> function p2 -> ... -> function pn -> expr
let name = fun p1 p2 ... pn -> expr
如何背诵:
首先是语法糖,
第二个是它内部真正做的,
第三个是来自 caml 的遗产。
现在 function
只接受一个参数,但它经常像这样使用 - 这些是 等价的, 你在 p3 上匹配:
let f1 p1 p2 p3 = match p3 with
| [] -> expr
| ...
let f2 p1 p2 = function
| [] -> expr
| ...
您看到第二个版本保存了一些源字符,消除了视觉混乱。或者更多:没有必要在不使用 p3 变量的情况下将值绑定到 p3,因为模式匹配是最好的绑定结构。