【问题标题】:OCaml how to fix module name collisionsOCaml 如何修复模块名称冲突
【发布时间】:2017-09-08 04:15:51
【问题描述】:

制作顶层时,模块名称不允许与内部编译器库冲突。

有哪些解决此类模块名称冲突的策略?

理想情况下,是否可以将一些参数传递给ocamlc,以指示它“修改”所有模块的名称以使用自定义前缀,如MyProject_? (从 OCaml ABI 的角度来看,并不是从字面上更改源文件)

下面的完整示例:

Sqrt.ml 包含

let sqrt x = x ** 0.5

Sqrt.mli 包含

val sqrt : float -> float

mktop 包含

#!/bin/bash

ocamlc -c Sqrt.mli -o Sqrt.cmi 
ocamlc -c Sqrt.ml  -o Sqrt.cmo

ocamlmktop -o sqrt_toplevel Sqrt.cmo

我可以生成一个包含我想要的函数的顶层。

% ./sqrt_toplevel
        OCaml version 4.04.0

# Sqrt.sqrt 4.5;;
- : float = 2.12132034355964239

如果我通过更改文件名将Sqrt 模块重命名为Parse,则名称与内部库冲突并且顶层无法链接。

mktop 现在是

#!/bin/bash

ocamlc -c Parse.mli -o Parse.cmi 
ocamlc -c Parse.ml  -o Parse.cmo

ocamlmktop -o parse_toplevel Parse.cmo

其他文件只需重命名为Parse.mlParse.mli

如果这样做,我会遇到与编译器库的命名冲突。

% ./mktop |& sed -e s:"$HOME":~:
File "Parse.cmo", line 1:
Warning 31: files Parse.cmo and ~/.opam/4.04.0/lib/ocaml/compiler-libs/ocamlcommon.cma(Parse) both define a module named Parse
File "_none_", line 1:
Error: Some fatal warnings were triggered (1 occurrences)
Exit 2

【问题讨论】:

    标签: namespaces ocaml


    【解决方案1】:

    除了使用与内部模块不冲突的名称之外,我没有看到有记录的方法来避免这个问题。

    这里是列出所有禁止名称的 Unix 命令,这至少是一些东西:

    $ cd ~/.opam/4.04.0/lib/ocaml/compiler-libs
    $ ocamlobjinfo ocamlbytecomp.cma ocamlcommon.cma ocamltoplevel.cma |
        awk '/^Unit name:/ { print $3}' | sort
    

    对我来说(现在使用 OCaml 4.03.0)有 96 个被禁止的名称。我写了一个脚本来验证所有 96 是否真的被禁止。

    作为旁注,尽管报告了错误,但实际上还是生成了顶层。而且,在快速测试中,它似乎有效。函数Parse.sqrt(例如)存在并计算正确答案。但可能有一些我没有遇到的问题。

    【讨论】:

      【解决方案2】:

      默认情况下,Dune/jbuilder 会将您的模块包装到以您的库命名的包含模块中。虽然这不会为您提供正确的命名空间,但您只需确保您的库名称是唯一的。

      sample project 可以具有以下结构:

      项目 ├── 生成文件 ├── proj.opam ├── README.md ├── sub1 │   ├── 库 │   │   ├── a.ml │   │   ├── a.mli │   │   ├── b.ml │   │   └── jbuild │   └── 测试 │   ├── a.ml │   ├── b.ml │   └── jbuild ├── sub2 │   ├── 斌 │   │   ├── bar_main.ml │   │   ├── foo_main.ml │   │   └── jbuild │   ├── 库 │   │   ├── a.ml │   │   └── jbuild │   └── 测试 │   ├── a.ml │   └── jbuild └── 测试 ├── jbuild └── run_tests.ml

      请注意我们如何拥有多个 a.mlb.ml 文件。

      sub1/lib 中的jbuild 文件是:

      (jbuild_version 1) ; name = 将所有源文件包装为子模块的超级模块的名称 ; public_name = ocamlfind 和 opam 的库名称 (图书馆 ((名称 proj_sub1) (public_name proj.sub1) (库(unix)) (概要“这是对 sub1 库的简短描述。”)))

      这将导致模块Proj_sub1.AProj_sub1.B 分别对应于sub1/lib/a.mlsub2/lib/b.ml。同样,我们也构建了Test_sub1.ATest_sub1.BProj_sub2.A等。

      【讨论】:

        【解决方案3】:

        使用 ocamlbuild,实现此目的的一种标准方法是将您的模块封装到 mlpack 中,如下所述:http://l-lang.blogspot.fr/2012/12/using-ocaml-packages-with-ocamlbuild.html

        文件:repo/A.ml

        let a = 3;;
        

        文件:repo/b.ml

        let b = A.a;;
        

        文件:repo.mlpack

        repo/A
        repo/B
        

        文件:main.ml

        Repo.B.b
        

        这解决了名称冲突问题,但强制您通过“超级模块”访问您的模块

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-08-21
          • 2011-07-17
          • 1970-01-01
          • 1970-01-01
          • 2016-04-30
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多