Syntax OCaml中function关键字与match的区别

Syntax OCaml中function关键字与match的区别,syntax,ocaml,Syntax,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)

我现在正在学习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,并且参数没有显式命名。

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>
可以写成

let f p1 p2 = ...
例如:

let dot (a, b) (c, d) = a *. c +. b *. d
您的第一个函数是使用这两个函数的组合(右边的简明
fun
函数

据我所知,这个函数与这个函数的作用相同

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)
这两个代码段的计算结果是相同的,这是正确的

有人能帮我理解第一个函数的语法吗

由于@JeffreyScofield似乎很好地回答了这一部分,我将集中讨论第二部分

如果存在任何差异,则说明两个函数的计算方式存在差异

tl;dr表示,没有区别,生产的组件实际上是相同的。我们将使用一个简单的斐波那契示例来显示使用
匹配
函数
符号发出的程序集

let rec fib n = match n with
| 0 -> 0
| 1 -> 1
| i -> fib (i - 1) + fib (i - 2)

两者都产生

fib:
    subq $24, %rsp
.L102:
    cmpq $1, %rax
    je .L100
    cmpq $3, %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 $24, %rsp
    ret
.L101:
    movq $3, %rax
    addq $24, %rsp
    ret
.L100:
    movq $1, %rax
    addq $24, %rsp
    ret
注意:我故意删除了
.align
s等

要验证这些函数是否生成相同的程序集(因此计算结果相同),只需将每个函数放在一个文件中,然后运行

$ ocamlopt -S fib-with-match.ml
$ ocamlopt -S fib-with-function.ml
当您
diff
这两者时,您应该看到它返回时没有任何差异:

$ 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留下的遗产

现在,
函数
只接受一个参数,但它通常是这样使用的-它们是等价的,您在p3上匹配:

let f1 p1 p2 p3 = match p3 with
 | []  -> expr
 | ...

let f2 p1 p2 = function
  | []  -> expr
  | ...

您可以看到,第二个版本保存了一些源字符,消除了视觉混乱。或者更多:不使用p3变量就不需要将值绑定到p3,因为模式匹配是最好的绑定构造。

是的,有点混乱,我们有3个函数定义语法,参数绑定端有模式匹配-是,Colin G.D.在OCaml(www.france-universite-numerique-mooc.fr)的函数式编程英文简介中有一个mooc。它还开着。他本周开始(由Xavier Leroy介绍)。嗨@V.Michel我知道这个mooc,我的老师是幕后操纵者,不过还是要谢谢你。
let f1 p1 p2 p3 = match p3 with
 | []  -> expr
 | ...

let f2 p1 p2 = function
  | []  -> expr
  | ...