从 OCaml 编译器打开模块而不构建自定义顶层
Opening modules from the OCaml compiler without building a custom toplevel
我想在我的 OCaml 输入文件的开头有几行代码,让顶层始终记住输入的最后一个表达式,名称为 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";;
这件事,我可以访问Toploop
和Parsetree
模块,但是我不能访问Location
模块!这是什么原因?我发现必须从我的源目录加载 .cmo
文件非常没有吸引力。
那么有没有一种方法可以在没有源代码树的情况下做我想做的事情?
或者换句话说:为什么Toploop
和Location
在这方面有区别?
简而言之,您应该加载的不是单个 .cmo
个文件,而是
#load "ocamlcommon.cma";;
在 +compiler-libs
目录中。
Parsetree
、Toploop
和 Location
之间的区别很微妙...
在 OCaml 中,只有将其目录添加到加载路径(通过 #directory "<dir>"
),数据类型及其构造函数才能访问。它们不需要目标代码加载(#load
)。
Parsetree
就是所谓的"mli only module":它只有数据类型定义,没有定义值。因此,Parsetree
中的所有内容都只能通过将其放入加载路径来访问。
Location
定义类型和值。它的数据类型和构造函数无需加载目标文件即可访问,但值需要加载。在这种情况下,对象 location.cmo
在您加载 ocamlcommon.cma
时加载,后者将其存档。
Toploop
是一个棘手的问题。您甚至可以在不加载 toploop.cmo
的情况下访问 Toploop
的值,因为 Toploop
已链接并且已经在 OCaml 顶层可用。
我想在我的 OCaml 输入文件的开头有几行代码,让顶层始终记住输入的最后一个表达式,名称为 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";;
这件事,我可以访问Toploop
和Parsetree
模块,但是我不能访问Location
模块!这是什么原因?我发现必须从我的源目录加载 .cmo
文件非常没有吸引力。
那么有没有一种方法可以在没有源代码树的情况下做我想做的事情?
或者换句话说:为什么Toploop
和Location
在这方面有区别?
简而言之,您应该加载的不是单个 .cmo
个文件,而是
#load "ocamlcommon.cma";;
在 +compiler-libs
目录中。
Parsetree
、Toploop
和 Location
之间的区别很微妙...
在 OCaml 中,只有将其目录添加到加载路径(通过 #directory "<dir>"
),数据类型及其构造函数才能访问。它们不需要目标代码加载(#load
)。
Parsetree
就是所谓的"mli only module":它只有数据类型定义,没有定义值。因此,Parsetree
中的所有内容都只能通过将其放入加载路径来访问。
Location
定义类型和值。它的数据类型和构造函数无需加载目标文件即可访问,但值需要加载。在这种情况下,对象 location.cmo
在您加载 ocamlcommon.cma
时加载,后者将其存档。
Toploop
是一个棘手的问题。您甚至可以在不加载 toploop.cmo
的情况下访问 Toploop
的值,因为 Toploop
已链接并且已经在 OCaml 顶层可用。