使用OCaml编译器打开模块而不需要构建自定义toplevel

3
我希望在我的OCaml输入文件的开头有几行代码,让toplevel始终记住上次输入的表达式,名称为it。 也就是说,我想要如下代码:
# 3 + 4;;
val it : int = 7
# it;;
val it : int = 7
# let foo = 42;;
val foo : int = 42
# it + 130;;
val it : int = 137
#

但我不想建立一个自定义的顶层或使用camlp5或任何花哨的东西。

目前我在做什么(在OCaml版本4.02.3中,我不知道为什么我有那个版本; 但我希望确切的版本并不重要?)是以下内容:

#directory "+compiler-libs";;

#load "/opt/src/ocaml-4.02.3/utils/warnings.cmo";;
#load "/opt/src/ocaml-4.02.3/parsing/location.cmo";;

let convert_phrase x =
  match x with
  | Parsetree.Ptop_def
        [{Parsetree.pstr_desc = Parsetree.Pstr_eval (e, a)}] ->
      Parsetree.Ptop_def
        ([{Parsetree.pstr_desc =
             Parsetree.Pstr_value (Asttypes.Nonrecursive,
               [{Parsetree.pvb_pat =
                   {Parsetree.ppat_desc =
                      Parsetree.Ppat_var (Location.mknoloc "it");
                    Parsetree.ppat_loc = Location.none;
                    Parsetree.ppat_attributes = []};
                 Parsetree.pvb_expr = e;
                 Parsetree.pvb_attributes = a;
                 Parsetree.pvb_loc = Location.none}]);
           Parsetree.pstr_loc = Location.none}])
  | x -> x;;

Toploop.parse_toplevel_phrase :=
  let parse_toplevel_phrase = !Toploop.parse_toplevel_phrase in
  fun x -> convert_phrase (parse_toplevel_phrase x);;

这种方法似乎行得通。

我的问题是:如果我只执行#directory "+compiler-libs";;,我可以访问ToploopParsetree模块,但我无法访问Location模块!原因是什么?我觉得从我的源目录加载.cmo文件非常不方便。

那么,有没有一种方法可以实现我想要的,而不需要拥有源代码树?

换句话说:为什么在这方面会有ToploopLocation之间的区别呢?

1个回答

8
简而言之,您应该加载的不是单独的.cmo文件,而是:
#load "ocamlcommon.cma";;

这段文字中提到的内容位于+compiler-libs目录中。

ParsetreeToploopLocation之间的区别是微妙的...

在OCaml中,只有将目录添加到加载路径(通过#directory "<dir>")才能访问数据类型及其构造函数。对它们不需要进行任何物体代码加载(通过#load)。

Parsetree被称为“仅限mli的模块”,它仅具有数据类型定义,没有定义任何值。因此,只有将所有内容放入加载路径后,才能访问Parsetree中的所有内容。

Location定义了类型和值。它的数据类型和构造函数可以在不加载对象文件的情况下访问,但值需要加载。在这种情况下,当您加载ocamlcommon.cma时,将加载对象location.cmo,并将其存档。

Toploop是一个棘手的问题。即使不加载toploop.cmo,您也可以访问Toploop的值,因为Toploop已链接并且在OCaml顶层环境中已经可用。


感谢您的出色回答!这完全解决了我的问题。 - Freek Wiedijk
1
我的困惑在于,作为 Coq 用户,我认为构造函数和函数是同一种东西,而 Parsetree.Ptop_def 是被允许的。这就是为什么我错过了 ToploopParsetree 之间的区别。再次感谢您的答复和进一步的澄清。 - Freek Wiedijk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接