无法仅在mli文件中定义例外

Lho*_*ooq 3 ocaml module exception signature

好吧,这主要是关于好奇心,但我发现它太奇怪了.

我们假设我有这个代码

sig.mli

type t = A | B
Run Code Online (Sandbox Code Playgroud)

main.ml

 let f = 
   let open Sig in
   function A | B -> ()
Run Code Online (Sandbox Code Playgroud)

如果我编译,一切都会工作.

现在,让我们尝试修改 sig.mli

sig.mli

type t = A | B
exception Argh
Run Code Online (Sandbox Code Playgroud)

和 main.ml

main.ml

 let f = 
   let open Sig in
   function 
     | A -> ()
     | B -> raise Argh
Run Code Online (Sandbox Code Playgroud)

让我们尝试编译它:

> ocamlc -o main sig.mli main.ml
  File "main.ml", line 1:
  Error: Error while linking main.cmo:
  Reference to undefined global `Sig'
Run Code Online (Sandbox Code Playgroud)

好吧,是不是因为我添加了例外?也许这意味着异常就像函数或模块一样,需要适当的实现.

但是,如果我写的话怎么办?

main.ml

 let f = 
   let open Sig in
   function A | B -> ()
Run Code Online (Sandbox Code Playgroud)

并尝试编译?

> ocamlc -o main sig.mli main.ml
>
Run Code Online (Sandbox Code Playgroud)

有效 !如果我不使用该异常,它会编译!

这种行为没有理由,对吧?(我在不同的编译器上测试了它,3.12.0,4.00.0,4.02.3和4.03.0并且它们都给出了相同的错误)

cam*_*ter 7

与变体不同,异常不是纯类型,需要在.ml文件中实现.使用以下代码编译以下代码ocamlc -dlambda -c x.ml:

let x = Exit

-- the output --
(setglobal X!
  (seq (opaque (global Pervasives!))
    (let (x/1199 = (field 2 (global Pervasives!)))
      (pseudo _none_(1)<ghost>:-1--1 (makeblock 0 x/1199)))))
Run Code Online (Sandbox Code Playgroud)

您可以看到(let (x/1999 = (field 2 (global Pervasives!)))..哪个意味着分配存储在2模块的nd位置的值Pervasives.这是价值Exit.例外有其价值,因此需要.ml.

变体不需要实现.因为它们的值可以纯粹根据它们的类型信息构造:构造函数的标记整数.我们不能将标记整数分配给异常(及其通用版本,开放类型构造函数),因为它们是公开定义的.相反,他们定义了他们的身份识别价值.ml.