1 / 2
13 / 17 · Files, Modules, and Programs
模块是一层墙
struct 是实现。签名决定外面能看见什么。
文件即模块:counter.ml 就是模块 Counter。里面的 let 默认都看得见。签名把不想给人用的函数藏起来,也可以把 type t = int 写成抽象的 type t,外面就只能当黑盒。
设计顺序是书里反复说的:先写调用的地方想要的接口,再写实现。不要先把具体类型漏出去,回头再补墙。
例子
utop
module Counter = struct
let zero = 0
let bump n = n + 1
let render n = Int.to_string n
endmodule Counter : sig val zero : int val bump : _ -> _ val render : _ -> _ end
let c = Counter.bump (Counter.bump Counter.zero)val c : int = 2
Counter.render c- : string = "2"
函子是「模块到模块的函数」
Inc 吃一个提供 x : int 的模块,吐出一个更大的模块。参数是签名,不是值。下面这段是书里的形状,书桌不跑函子语法;你要感到的是:实现可以换,签名不变。
module type X = sig
val x : int
end
module Inc (M : X) = struct
let y = M.x + 1
end
module A = Inc (struct let x = 3 end)改一改
改完再跑
解释器覆盖书前半的核心:函数、标签参数、模式、记录、变体、ref、模块,以及简化的 Map 和 JSON。没有 GADT 细化、Async 和独立编译。
先预测,再对照
2 / 2