OCaml,像 Emacs 一样扩展程序

OCaml, extends a program a la Emacs

我喜欢 OCaml,我正在等待我的 Real World OCaml 副本! 我是一个初学OCaml程序员,只知道functionnal部分,有点命令式,但对模块、函子、对象等了解不多...

对于某种解释器项目,我做了一种类似于新手 emacs 的评估。我保留了一个三元组列表,其中包含作为字符串的命令名称绑定列表、一个用于描述的字符串和要调用的 ocaml 函数。主循环只是在列表中查找匹配的条目并调用函数。

那么添加新功能就非常简单了,您只需编写一个函数并在列表中添加一个条目即可。

我喜欢像 Emacs 一样可自扩展的概念,这很容易扩展,但不是真正的自扩展。

我可以使用 OCaml 使程序自扩展吗? 我该怎么做?

我知道 Emacs 是如何工作的,它是一个很大的虚拟机,所以它自己解释代码并修改它的运行时环境,但是有没有办法通过用户添加的模块向 OCaml 程序添加功能?还是别的?

ps : 如果我的项目听起来很基础,请不要笑我,但我是初学者!

谢谢

Could I make a program self extendable with OCaml?

是的,你可以做一个 self-extensible 解释器。

Is there a way to add functionnalities to an OCaml program with user added modules?

是的,但是。 OCaml 交互式提示就是这样一个可扩展的程序。 MetaOCaml 是 OCaml 的 multi-stage 编程扩展,支持在运行时增量编译新机器代码。 [Wikipedia] 除非你 piggy-back 使用其中之一,您正在查看 non-trivial 工程任务。

How would I do that?

具体取决于你想做什么,你也可以看看OCaml as Scheme or Scheme interpreter in Standard ML。然后你基本上必须构建一个 read-eval-print 循环来解析输入语言并相应地修改你的 three-tuple 。但不能直接使用 OCaml。

另一种解决方案可能是使用 Ocaml dynamic loading facilities, e.g. the Dynlink 模块。例如,每个动态加载的共享模块可以将条目添加到一些全局散列 table 将字符串名称映射到函数(相同类型)等......这个初始化 -运行 它的顶级表达式 -动态加载的模块发生在它的加载时间(当你调用 Dynlink.loadfile 时),有点像 POSIX dlopen

的旧 _init 函数

例如,您可以让您的程序在运行时发出一些 Ocaml 代码;将其编译成一个可加载的动态库 using ocamlopt -shared ;然后 Dynlink.loadfile 那个图书馆。该库的初始化部分将使用主程序中提供的一些适当函数注册闭包。

或者,在 Ocaml 中编写(或使用)一些虚拟机或解释器。

您也可以使用一些 JIT 库,例如Ollvm,并生成一些 C-like 代码(可能在主程序的某些 C 胶代码中使用 dlopen)。

但作为 MetaOcaml 可能是更好的方法。

顺便说一句,也许你想要一些 Common Lisp 实现?


示例:

(未经测试的代码!一些细节可能是错误的)

您的主程序 prog.ml 将包含

let ht = Hashtbl.create 53;;
let add_name_fun (name : string) (f : int -> int) = 
   Hashtbl.add ht name f;;
(* here you might emit the 'plugin.ml' file and fork its compilation *) 
Dynlink.loadfile "plugin.cmxs";;
(* as an example we apply every added name & function to 3 *)
Hashtbl.iter ht (fun n f) -> Printf.printf "n=%s (f 3)=%d\n" n (f 3);;

您的 prog.mli 将包含:

  val : add_name_fun : string -> (int -> int) -> unit;;

您的 plugin.ml 将包含

  Prog.add_name_fun "foo" (fun x -> x+3);;

但是我没有测试代码。

PS。在 POSIX 系统上,您可以使用 dlopen & dlsym. My GCC MELT is doing that. See also this.

在 C 中执行类似的操作

注意:如果您喜欢 meta-programming 方法,请阅读 J.Pitrat's blog 和书籍。