`let` 从 ocaml 中的记录中进行双关语

`let` field punning from records in ocaml

非常微不足道的问题,但这是否有效

  type rtype = { field : int }
  let r : rtype = assert false

  let _ = r |> fun { field } -> 0
  let _ =  let { field } = r in 0

而这不会

  module type rsig = sig
    type r = { somefield : 'a. 'a -> int }
    val inj : r
  end

  module R : rsig = struct
    type r = { somefield : 'a. 'a -> int }
    let inj : r = { somefield = (fun _ -> 0) }
  end

  let _ = R.inj |> fun { somefield } -> 0
  let _ = let { somefield } = R.inj in 0  (* Unbound record field somefield  *)

不是因为 let 双关,而是因为类型驱动 record field names disambiguation。它不是主要的,甚至会有警告告诉您您的代码取决于它的存在。在第一种情况下,类型检查器从应用程序中推断出函数的类型。在第二种情况下,它没有信息类型来推断 somefield 来自模块 R1.

在OCaml中,字段名是在模块的命名空间中定义的,所以最好明确指定模块名,例如

let _ = let { R.somefield} = R.inj  in 0

或者,您可以限制类型以确保类型检查器在消除记录名称歧义时知道类型,例如,

let {somefield} : R.r = R.inj in 0

或者,

let foo : R.r -> unit = function {somefield} -> ()

1)在第二种情况下,let {somefield} = R.inj in 0类型检查器从左侧开始推理,并且还不知道右侧具有类型 R.r,如果您将代码重写为 let r = R.inj in r.somefield; 0,它将计算出 somefield 来自 R.