OCaml Introduction and Basics of OCaml (三)

115 阅读2分钟

这是我参与11月更文挑战的第4天,活动详情查看:2021最后一次更文挑战

参数标记和可选参数

对于参数比较多的函数(尤其是那些有相同类型参数),可以使用标记。OCaml支持对函数的参数进行标记。比如:

utop # let f ~name1: arg1 ~name2:arg2 = arg1 + arg2;;
val f : name1:int -> name2:int -> int = <fun>

utop # f ~name2: 3 ~name1: 4;;
- : int = 7

参数的标记通常和变量名一样。OCaml 提供对待两者是一样的,如下面的代码是等价的

utop # let f ~name1: name1 ~name2: name2 = name1 + name2;;
utop # let f ~name1 ~name2 = name1 + name2;;

也支持对参数指定显式的类型

utop # let f ~name1:(arg1:int) ~name2:(arg2:int) = arg1 + arg2;;

当然有些参数是可选的,

utop # let f ?name: (arg1=8) arg2 = arg1 + arg2;;
val f : ?name:int -> int -> int = <fun>

utop # f ~name:2 7;;
- : int = 9

utop # f 7;;
- : int = 15

Partial application

比如,下面有两个函数

utop # let add x y = x + y;;
utop # let addx x = fun y -> x + y;;

其中,函数addx的类型是 int -> int -> int;而 add的类型也为int -> int -> int。从这一点上可以看出它们是相同的函数。但是addx的形式很有趣,它仅仅只需要复制给一个参数。

utop # let add5 = addx 5;;
val add5 : int -> int = <fun>

utop # add5 2;;
- : int = 7

并且使用add也可以达到相同的效果

utop # let add5 = add 5;;
val add5 : int -> int = <fun>

utop # add5 2;;
- : int = 7

这就是所谓的partial application: 我们能够调用函数的时候只传递部分参数。为什么这是OK的?因为下面的三个函数在语法上不同但是语义是相同的。换句话说,就是用不同的方法来表示相同的计算式:

utop # let add x y = x + y;;
utop # let add x = fun y -> x + y;;
utop # let add = fun x -> (fun y -> x + y);;

OCaml中的每一个函数仅仅只有一个参数

为什么?通常来说,

let f x1 x2 ... xn = e;;

在语法上等同于

let f =
  fun x1 ->
    (fun x2 ->
       (...
          (fun xn -> e)...))

所以,可以认为函数fn个参数,等同于这个函数只有一个参数,并返回一个函数,并且这个函数的类型为

t1 -> t2 -> t3 -> t4

更严谨点说是,

t1 -> (t2 -> (t3 -> t4)))

这被称作类型的右结合率。

操作符可以被看作成函数

The addition operator + has type int->int->int. It is normally written infix, e.g., 3+4. By putting parentheses around it, we can make it a prefix operator:

# (+);;
- : int -> int -> int = <fun>

# (+) 3 4;;
- : int = 7

# let add3 = (+) 3;;
- : int -> int = <fun>

# add3 2;;
- : int = 5

let 表达式

syntax

let x = e1 in e2

Dynamic sematics:

为了计算let x = e1 in e2

  • 计算e1得到值v1

  • v1替代e2中的x,产生一个新值e2'

  • 计算e2'得到v2

  • 整个表达式的值为v2

utop # let x = 1 + 4 in x * 3;;
- : int = 15

Static semantics.

  • If e1:t1 and if under the assumption that x:t1 it holds that e2:t2, then (let x = e1 in e2) : t2.

\