dune-ocaml :没有为以下模块提供实现:

dune-ocaml : No implementations provided for the following modules:

我尝试用 Dune 编译 OCaml 代码,但出现以下错误:

Error: No implementations provided for the following modules:
CallccBp referenced from bin/.CallccTest.eobjs/native/dune__exe__CallccTest.cmx

通过执行命令:$ dune build

我的项目层次结构如下:

callcc/

    bin/

      callccTest.ml

      dune
        [

         (executable

         (name callccTest)

         (libraries CallccBp))

        ]
   lib/
      CallccBp.mli

      dune
       [

       (library

       (name CallccBp)

       (modules_without_implementation CallccBp))
        ]

   test/

    callccTest.ml

     dune [
      (test
       (name callccTest))
       ]

callcc.opam

dune-project

我该如何解决这个问题?

错误消息抱怨模块 CallccBp 没有实现(也就是没有 ml 文件)。在不知道 CallccBp 的内容的情况下,此模块可能包含异常或扩展构造函数声明(或任何其他类型的运行时组件)。您的第一个修复应该是添加一个 callccBp.ml 文件并删除 (module_without_implementation ...) 行。

看看你对octachron的讨论,让我们从基础开始:

my_module.mli

File where you declare the signatures of your values, modules etc. Not mandatory, I'd advise not using them if you start with OCaml

my_module.ml

File where you implement your values, modules etc. Mandatory since these are the files that make your program run

让我们通过一个玩具项目来看一下:

.
├── bin
│   ├── dune
         (executable
          (name main)
         )
│   └── main.ml
├── dune-project
├── lib
│   ├── dune
         (library
          (name my_module)
         )
│   └── my_module.ml
└── program.opam

如果我想在 bin/main.ml 中使用来自 my_module 的值,我必须:

  • 具有 my_module.ml
  • 中的值
  • 在我的 bin/dune 文件中添加 (libraries my_module)
  • 将这些值与 My_module.<name_of_value>
  • 一起使用

所以这看起来像:

.
├── bin
│   ├── dune
         (executable
          (name main)
          (libraries my_module)
         )
│   └── main.ml
         let () =
           let b = My_module.incr 3 in
           Printf.printf "%d\n" b
├── dune-project
├── lib
│   ├── dune
│   └── my_module.ml
         let incr a = a + 1
└── program.opam

现在,让我们回到您的层次结构:

callcc/
    bin/
      callccTest.ml
      dune
        [
         (executable
         (name callccTest)
         (libraries CallccBp))
        ]
   lib/
      CallccBp.mli
      dune
       [
       (library
       (name CallccBp)
       (modules_without_implementation CallccBp))
        ]
   test/
    callccTest.ml
     dune [
      (test
       (name callccTest))
       ]
callcc.opam
dune-project

一切看起来都很好,除了 CallccBp.mli 只是一个接口,而不是一个实现。作为初学者,您可以删除此文件,创建 CallccBp.ml 并填充以下两个函数:

CallccBp.ml

let callcc = failwith "TODO"
let throw = failwith "TODO"

如果你编译,dune 不应该抱怨,现在你所要做的就是提供一个比 failwith "TODO"

更有用的实现

如果我们回到我们的玩具项目,看看您为什么想要一个 mli 文件:

.
├── bin
│   ├── dune
         (executable
          (name main)
          (libraries my_module)
         )
│   └── main.ml
         let () =
           let b = My_module.incr 3 in
           Printf.printf "%d\n" b
├── dune-project
├── lib
│   ├── dune
│   └── my_module.ml
         let dummy _ = failwith "USELESS"
         let incr a = a + 1
│   └── my_module.mli
         val incr : int -> int
         (** [incr d] will return [d] incremented by 1. Highly efficient. Trust me. *)
└── program.opam

我可以在 bin/main.ml 中使用 My_module.incr 但不能在 My_module.dummy 中使用,因为 mli 文件中没有显示它,因此无法在 my_module.ml。作为奖励,my_module.mli 文件是图书馆用户的入口点,他们不想知道它是如何实现的,但只想知道可用的值、它们的类型以及通常它们的作用来使用它来自评论。


modules_without_implementation 节用于 mli 不需要实现的文件,即类型声明文件,因此模块如下所示:

AST.mli

type ('a, 'b) res = Ok of 'a | Error of 'b
type num = Int of int | Float of float
type person = {id : int; name : string; age : num}

您可以像这样在另一个文件中使用它们:

file.ml

type t = {player1 : AST.person; player2 : AST.person}

let whos_older p1 p2 =
  Printf.printf "%s is older\n"
    (if p1.AST.age > p2.AST.age then p1.name else p2.name)

但这在开始时并不是很有用,因为我再次建议不要在开始时接触 mli 个文件