函数关键字与OCaml匹配的区别

时间:2015-10-21 17:52:24

标签: 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) -> tree_to_list t1 (tree_to_list2 acc t2)

但是,我不理解第一个函数背后的语法。我发现关键字功能令人困惑。它应该只采用一个参数:

function x -> x + 2

有人可以帮我理解第一个函数的语法,以及两个函数的评估方式是否存在差异。提前谢谢。

4 个答案:

答案 0 :(得分:9)

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

您的第一个功能是使用两者的组合(右侧是简洁的funfunction

答案 1 :(得分:4)

  

据我了解,此功能与此功能相同

你是正确的,因为两个代码片段的评估是相同的。

  

有人可以帮我理解第一个函数的语法

由于@JeffreyScofield似乎已经很好地回答了这一部分,我将重点关注第二部分。

  

如果评估这两个函数的方式有何不同

tl; dr没有区别,生产的组件实际上是相同的。我们将使用一个简单的Fibonacci示例来显示使用match withfunction符号发出的程序集。

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 $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等。

要验证这些产生相同程序集的声明(因此评估相同),您只需将每个函数放入一个文件然后运行

$ 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有一个可用于模式匹配的参数。因此,它是有效的语法糖。

来源:

答案 2 :(得分:1)

我在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,因为模式匹配是最好的绑定结构。

答案 3 :(得分:0)

第一个函数不是明确命名其参数。 您可以对添加2的函数执行相同的操作:

let f = (+) 2;;

这将为任何数字添加2,并且未明确命名arg。