精选 OCaml 常用指令与核心速查备忘单,涵盖高频用法、配置参数与实用技巧。 本 OCaml 备忘单为您提供 OCaml 函数式编程语言的核心语法与常用 API 快速检索手册。
let () =
let message = "Hello, World!" in
Printf.printf "%s\n" message
编译与运行 (Compile and Run)
$ ocamlc -o hello.byte hello.ml
$ ./hello.byte
使用 Dune 构建与运行 (Build & Run with Dune)
$ dune build hello.exe
$ _build/default/hello.exe
# 也可以直接运行
$ dune exec ./hello.exe
详细信息请参阅 dune 官方文档。
使用 opam 安装外部扩展模块:
$ opam install hex
全局打开模块 (Global Open)
open Hex
局部打开模块 (Local Open)
Hex.of_string "hex string"
let open Hex in
of_string "to hex"
单行与多行注释 (Line & Block Comments)
(* 单行注释 *)
(* 多行注释
* 当我们需要详细说明
* 某些复杂逻辑时 *)
(* 外层注释
(* 支持嵌套注释 *)
外层注释结束 *)
档注释 (Documentation Comments)
val sum : int -> int -> int
(** [sum x y] 返回两个整数
[x] 和 [y] 的加和总值 *)
Unit 类型
注意:# 表示在交互式终端 (Toplevel) 中执行指令及返回结果
# ();; (* 相当于 C 语言中的 void *)
- : unit = ()
核心基础类型 (Basic Types)
# 5 ;; (* 整数 int *)
- : int = 5
# 3.14 ;; (* 浮点数 float *)
- : float = 3.14
# true ;; (* 布尔值 bool *)
- : bool = true
# false ;;
- : bool = false
# 'a' ;; (* 字符 char *)
- : char = 'a'
# "a string" ;; (* 字符串 string *)
- : string = "a string"
# String.to_bytes "hello" ;; (* 字节数组 bytes *)
- : bytes = Bytes.of_string "hello"
# (3, 5);; (* 元组 tuple *)
- : int * int = (3, 5)
# ref 0;; (* 可变引用 reference *)
- : int ref = {contents = 0}
Options 与 Results 包装类型
# Some 42;;
- : int option = Some 42
# Ok 42;;
- : (int, 'a) result = Ok 42
# Error "404";;
- : ('a, int) result = Error 404
数组 (Arrays)
# [|0; 1; 2; 3|];; (* 创建数组 *)
- : int array = [|0; 1; 2; 3|]
# [|'u'; 's'; 'c'|].(1);; (* 访问数组元素 *)
- char = 's'
数组是可变的 (Mutable):
let scores = [|97; 85; 99|];;
- : int array = [|97; 85; 99|]
# scores.(2) <- 89;; (* 修改更新数组元素 *)
- unit = ()
# scores;;
- : int array = [|97; 85; 89|]
列表 (Lists)
# [1; 2; 3];;
- : int list = [1; 2; 3;]
# ["a"; "str"; "lst"];;
- : string list = ["a"; "str"; "lst"]
列表是不可变的 (Immutable):
# let lst = [1; 2; 3];;
- : int list = [1; 2; 3]
# let new_lst = 0 :: lst;; (* 头部追加元素生成新列表 *)
- : int list = [0; 1; 2; 3]
# new_lst @ [4;5;6];; (* 拼接合并两个列表 *)
- : int list = [0; 1; 2; 3; 4; 5; 6]
记录体 (Records)
用于将相关关联的数据打包声明:
type person = {
name: string;
age: int
}
# let zeno = {name = "Zeno"; age = 30};;
val zeno : person = {name = "Zeno"; age = 30}
变体类型 (Variants)
定义多个不同但相互关联的类型分支:
type shape =
| Circle of float
| Rectangle of float * float
# let my_shape = Circle 5.0;;
- : shape = Circle 5.
类型别名 (Aliases)
为复杂或高频使用的类型赋予具名含义:
type point = float * float
# let origin: point = (0.0, 0.0);;
val origin : point = (0., 0.)
单参数函数
let add_one x =
let result = x + 1 in
result
# add_one 1;;
- : int = 2
多参数函数
let sum x y =
let result = x + y in
result
# sum 1 2;;
- : int = 3
元组参数函数
let str_concat (x, y) =
x ^ " " ^ y
# str_concat ("Hello", "OCaml") ;;
- : string = "Hello Ocaml"
rec 关键字
所有递归调用的函数均必须显式添加 rec 关键字:
let rec factorial n =
if n < 1 then 1 else n * factorial (n - 1)
上述普通递归在深层调用时可能引发栈溢出 (Stack overflow)。
尾递归优化 (Tail Recursion)
借由辅助累加器参数实现高效尾递归:
let rec factorial_helper n acc =
if n = 0 then acc
else factorial_helper (n - 1) (n * acc)
注意最后一次表达式调用即为递归函数自身:
let factorial n = factorial_helper n 1
应用运算符 (Application Operator)
由右向左读取求值,优先计算 sum 2 3:
(* 计算 log(2 + 3) *)
# log @@ float_of_int @@ sum 2 3 ;;
- : float = 1.609...
管道运算符 (Pipeline)
(* 计算 log((x + y)!) *)
# sum 2 3
|> factorial
|> float_of_int
|> log ;;
- : float = 4.787...
|> 将前一个函数的返回值作为输入传给管道中的下一个函数
If 表达式
let is_pos x =
if x > 0 then "positive" else "negative"
If else if 多分支
let f x =
if x > 3 then "gt 3"
else if x < 3 then "lt 3"
else "eq 3"
模式匹配 (Pattern Matching)
let is_pos x =
match x > 0 with
| true -> "positive"
| false -> "negative"
For 循环
for i = 1 to 5 do
print_int i
done
While 循环
注意需要借助 ref 可变引用使条件最终变为 false 结束循环:
let i = ref 0 in
while !i < 5 do
print_int !i;
i := !i + 1
done
比较运算符
= (* 等于 *)
<> (* 不等于 *)
> (* 大于 *)
< (* 小于 *)
>= (* 大于等于 *)
<= (* 小于等于 *)
算术运算符
(* 整数运算符 浮点数运算符 *)
+ +. (* 加法 *)
- -. (* 减法 *)
* *. (* 乘法 *)
/ /. (* 除法 *)
** (* 求幂 *)
查找与过滤 (Searching & Filtering)
# let lst = [1; 2; 3];;
val lst : int list = [1; 2; 3]
# List.filter (fun x -> x mod 2 = 0) lst;;
- : int list = [2]
# List.find (fun x -> x = 4) lst;;
Exception: Not_found
# List.sort compare [2; 1; 3];;
- : int list = [1; 2; 3]
转换与映射 (Applying Transformations)
(* 遍历列表并对每项执行函数 f *)
List.iter f lst
(* 将映射函数作用于每个元素 *)
(* 例:将列表中的元素翻倍 *)
List.map (fun x -> x + x) lst
(* 在元素之间应用运算符归约 *)
(* 例:1 + 2 + 3 *)
List.fold_left (+) 0 lst
定义与访问
let scores =
[("math", 91); ("phil", 89); ("stats", 94)]
# List.assoc "stats" scores;;
- : int = 94
# List.mem_assoc "math" scores;;
- : bool = true
拆分与合并
# List.split scores;;
- : string list * int list = (["math"; "phil"; "stats"], [91; 89; 94])
# List.combine [1;2;3] [4; 5; 6];;
- : (int * int) list = [(1, 4); (2, 5); (3, 6)]
关联列表类似字典或 Hashmap 哈希表。
哈希表是可变的 (Mutable)。
初始化与添加数据
# let my_htable = Hashtbl.create 3;;
val my_htable : ('_weak1, '_weak2) Hashtbl.t = <abstr>
# Hashtbl.add my_htable "A" "John";
Hashtbl.add my_htable "A" "Jane";
Hashtbl.add my_htable "B" "Max";;
数据查找
# Hashtbl.find my_htable "A";;
- : string = "Jane"
(* 查找所有匹配项 *)
# Hashtbl.find_all my_htable "A";;
- : string list = ["Jane"; "John"]
Map 是不可变的键值对关联表。
初始化与添加数据
(* 使用 Map.Make 函子创建自定义 map 模块 *)
# module StringMap = Map.Make(String);;
let books =
StringMap.empty
|> StringMap.add "Dune" ("Herbet", 1965)
|> StringMap.add "Neuromancer" ("Gibson", 1984)
查找数据
(* find_opt 返回包裹在 option 中的值,不存在返回 None *)
# StringMap.find_opt "Dune" books;;
- : (string * int) option = Some ("Herbet", 1965)
(* find 直接返回关联值,不存在抛出 Not_Found *)
# StringMap.find "Dune" books;;
- : string * int = ("Herbet", 1965)
插入与移除数据
由于 Map 不可变,操作会返回全新的 Map 对象:
let more_books = books
|> StringMap.add "Foundation" ("Isaac Asimov", 1951)
let less_books =
|> StringMap.remove "Dune"
过滤筛选:
let eighties_books =
StringMap.filter
(fun _ (_, year) -> year > 1980 & number < 1990) books
遍历打印数据
let print_books map =
StringMap.iter (fun title (author, year) ->
Printf.printf "Title: %s, Author: %s, Year: %d\n" title author year
) map
# let () = print_books eighties_books;;
Title: Neuromancer, Author: Gibson, Year: 1984