OCaml 5.5.0 released

OCaml 5.5.0 released

We have the pleasure of celebrating the birthday of Blaise Pascal by announcing the release of OCaml version 5.5.0.

我们很高兴在布莱兹·帕斯卡(Blaise Pascal)诞辰之际,宣布 OCaml 5.5.0 版本的发布。

Some of the highlights in OCaml 5.5.0 are:

OCaml 5.5.0 的一些亮点包括:

Module-dependent Functions

模块依赖函数

Modules can now be used as function arguments in a form of lightweight functors.

现在,模块可以作为函数参数使用,形式类似于轻量级函子(functors)。

For instance, we can define a function for printing a map generated by the Map.Make functor:

例如,我们可以定义一个函数来打印由 Map.Make 函子生成的映射(map):

let pp_map (module M: Map.S) pp_key pp_v ppf set =
  if M.is_empty set then Format.fprintf ppf "ø"
  else
    let pp_sep ppf () = Format.fprintf ppf ",@ " in
    let pp_binding ppf (k,v) = Format.fprintf ppf "@[%a@ =@ %a@]" pp_key k pp_v v in
    Format.fprintf ppf "@[{@ %a@ }@]" (Format.pp_print_seq ~pp_sep pp_binding) (M.to_seq set)

We can then apply this function on a string map:

然后,我们可以将此函数应用于字符串映射:

module String_map = Map.Make(String)

with:

使用方式如下:

let () =
  let m = String_map.of_list ["Zero", "Zero"; "One", "Un"] in
  let pp_str = Format.pp_print_string in
  Format.printf "%a@." (pp_map (module String_map) pp_str pp_str) m

Compared to first-class modules, the type of the function pp_map:

与一等模块(first-class modules)相比,pp_map 函数的类型:

type 'a printer = Format.formatter -> 'a -> unit
val pp_map: (module M: Map.S) -> M.key printer -> 'a printer -> 'a M.t printer

is dependent over the value of the module S, and thus the function can only be applied over a statically known module:

依赖于模块 S 的值,因此该函数只能应用于静态已知的模块:

let f (): (module Map.S) =
  if Random.bool () then (module Map.Make(Int)) else (module Map.Make(Float))
let fail = pp_map (f ())

Error: This expression has type (module M : Map.S) -> (Format.formatter -> M.key -> unit) -> (Format.formatter -> ‘a -> unit) -> Format.formatter -> ‘a M.t -> unit but an expression was expected of type (module Map.S) -> ‘b The module M would escape its scope This function is module-dependent. The dependency is preserved when the function is passed a static module argument (module M : S) or (module M). Its argument here is not static, so the type-checker tried instead to change the function type to be non-dependent.

错误:此表达式的类型为 (module M : Map.S) -> (Format.formatter -> M.key -> unit) -> (Format.formatter -> ‘a -> unit) -> Format.formatter -> ‘a M.t -> unit,但期望的类型为 (module Map.S) -> ‘b 模块 M 将逃逸其作用域 此函数是模块依赖的。当函数被传递一个静态模块参数 (module M : S) 或 (module M) 时,这种依赖关系会被保留。此处其参数不是静态的,因此类型检查器尝试将其函数类型更改为非依赖类型。

Relocatable Compiler

可重定位编译器

A compiler installation can now be moved or copied with no risk of hard-to-debug errors due to mixing incompatible bytecode runtime interpreters.

现在,编译器安装目录可以被移动或复制,而不会因为混合了不兼容的字节码运行时解释器而导致难以调试的错误。

In practice, this means that creating a local switch when there is a global switch with the same compiler version and configuration available can be done by cloning the global switch rather than recompiling the whole compiler.

在实践中,这意味着当存在具有相同编译器版本和配置的全局 switch 时,创建本地 switch 可以通过克隆全局 switch 来完成,而无需重新编译整个编译器。

This should considerably reduce the time required to create new local opam switches out-of-the-box.

这将显著减少开箱即用创建新的本地 opam switch 所需的时间。

Polymorphic Functions as Function Arguments

作为函数参数的多态函数

Higher-rank polymorphic functions can now be defined directly by using an explicit type annotation in a function argument.

现在,可以通过在函数参数中使用显式类型注解,直接定义高阶多态函数。