You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Dune仅暴露`Foo__.Bar`模块而非`Foo.Bar`?

Dune项目中模块访问路径不符合直觉的问题

注:utop 通过 dune utop 启动。

问题场景

通过 dune init project foo 初始化项目后,在lib目录下创建两个文件:lib/foo.ml 和 lib/bar.ml。

lib/foo.ml 内容:

let x = 3

lib/bar.ml 内容:

let x = 4

在utop中可以正常通过 Foo.x 访问foo.ml中的值:

utop # Foo.x;;
- : int = 3

但访问bar.ml中的值时,路径却不符合直觉:

utop # Foo.Bar.x;;
Error: Unbound module Foo.Bar
utop # Bar.x;;
Error: Unbound module Bar
utop # Foo__Bar.x;;
- : int = 4
utop # Foo__.Bar.x;;
- : int = 4

原本预期可以通过 Foo.Bar.x 访问,或者说,通常应该能通过 Foo.<首字母大写的文件名>.something 来访问lib目录下文件中的内容。比如Re库的lib目录下有pcre.ml文件,对应的模块可以通过Re.Pcre.exec访问:

utop # #require "re";;
utop # Re.Pcre.exec;;
- : rex:Re.re -> ?pos:int -> string -> Re.substrings = <fun>

这个问题在编写测试时同样存在:
测试目录下的test/dune配置:

(test
 (name foo)
 (libraries foo))

测试代码test/foo.ml中,必须写Foo__.Bar.x而非Foo.Bar.x:

assert (Foo__.Bar.x == 3)

执行测试的结果:

%dune test
File "test/dune", line 2, characters 7-10:
2 |  (name foo)
           ^^^
Fatal error: exception Assert_failure("test/foo.ml", 1, 0)

如果改成Foo.Bar.x:

assert (Foo.Bar.x == 3)

则无法通过编译:

%dune test
File "test/foo.ml", line 1, characters 8-17:
1 | assert (Foo.Bar.x == 3)
            ^^^^^^^^^
Error: Unbound module Foo.Bar

而Re库的测试代码可以直接通过Re.FooBar这样的路径访问库模块。

疑问

为何无法通过Foo.Bar访问模块?当前行为并未限制访问lib/bar.ml中的内容,但Foo.Bar比Foo__.Bar更符合直觉、更易使用。


尝试过的解决方案

1. 使用-for-pack标志

搜索到相关问题后,尝试在lib/dune中添加该标志:

(library
 (name foo)
 (flags -for-pack))

但没有任何效果。

2. 设置(wrapped false)

根据Dune手册,添加该配置可以将模块暴露在顶层:

(library
 (name foo)
 (wrapped false))

此时在utop中可以直接访问:

utop # Bar.x;;
- : int = 4

但正如文档所述,这会污染全局命名空间,因此不推荐使用。

版本信息

  • OCaml: 4.14.1
  • Dune: 3.9.1

内容的提问来源于stack exchange,提问作者toku-sa-n

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 10:14:53