Grammar

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
(* 整数除法 *)
65 / 60 (* ==> 1 *)

(* 取模 *)
65 mod 60 (* ==> 5 *)

(* 浮点数乘法,和整数运算相比,都需要加一个 "." *)
3.14 *. 2. (* ==> 6.28,注意这里是 *. *)
1.0 +. 2.0 (* ==> 3.0,*)

(* Bool 运算 *)
&&
||
= (* structural equality 相等 *)
<> (* structural equality 不相等 *) (* 用这两个就行了 *)
==, != (* physical equality *)

(* String *)
"abc" ^ "d" (* 字符串拼接 *)
"abc".[1] (* ==> 'b',取字符 *)

(* 类型转换 *)
string_of_int 42 (* ==> "42" *)
int_of_string "43" (* ==> 43 *)

(** assertion *)
let () = assert (f x = y)
(* 语法是 assert e,如果 e 为 true 那么无事发生,返回 unit `()` *)

(** if-else *)
if ... then ...
else if ... then ...
else ...

(* let-in 和 Haskell 一样 *)
let x = 42 in x+1 (* => 43 *)

(** 用 ; 在同一行里塞多个 expression *)
e1; e2; e3 (* 先 evaluate e1,再是 e2, e3 *)
(* 如果 e1 有返回值,上面的写法会报 warning.
可以用 `ignore: 'a -> unit = <fun>` 手动忽略返回值 *)
(ignore e1); e2

Functions

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
(** 用 let 定义普通函数 *)
let f x = ...

(** 用 rec 定义递归函数 *)
let rec f x = ...

(** 用 fun ... -> ... 定义匿名函数 *)
let inc = fun x -> x + 1
(* val inc: int -> int *)

(** pipeline `| >`, 本质相等于 *)
f (g x)
(* 等价于 *)
x |> g |> f

(** Labeled/Optional Argument *)
(* 用 <func> ~<label>:<name_in_body> = name_in_body ... 进行定义 *)
f ~name1:arg1 ~name2:arg2 = arg1+arg2

(* :arg1 也可以省略,默认和参数名字一样 *)
f ~name1 ~name2 = name1 + name2

(* 用 ? 而不是 ~ 表示可选参数,但是必须提供默认参数 *)
f ?name1:(arg1=8) arg2 = arg1 + arg2

(* 用 ~<name>:<value> 表示带参数的函数调用,不管在函数定义里,是用 ~ 标记的参数还是 ? 标记的可选参数 *)
f ~name1:3 ~name2:4
Function Associativity

可以这样认为:每一个 OCaml function 都只接受一个参数,多参数的函数可以看作是 x -> (some other function) 例如

1
2
3
t1 -> t2 -> t3 -> t4
(* 等价于 *)
t1 -> (t2 -> (t3 -> t4))

因此,函数本质是 right associative 的.

但是,函数调用是 left associative 的,e1 e2 e3 e4 会被解释为 ((e1 e2) e3) e4

Documentation

(** ... *) 表示文档,用方括号包起来 [] 以 monospace 字体显示,同时也有 @param 等等解释性 tag,以及 Raises:, Requires: 的解释性标签.

Printing

1
2
3
(** 像 C/Java 那样进行格式化输出 *)
Printf.printf "%s: %F\n%!" name num
(* 这里的 %! 表示 flush output buffer,类似于 std::cout.flush() *)

Debugging

可以在解释器界面用 #trace fib 的方式检查中间输出,或者用 ocamldebug 程序.