我喜欢OCaml,我等着我的真实世界OCaml副本! 我是初学者OCaml程序员,只知道函数部分,有点必要,但关于模块,仿函数,对象等等并不多...
对于某种翻译项目,我做了类似新手emacs的评估。我保留一个三元组列表,其中包含一个命令名绑定列表作为字符串,一个描述字符串和要调用的ocaml函数。主循环只查找列表中的匹配条目并调用该函数。
然后添加新的功能非常简单,只需编写一个函数并在列表中添加一个条目。
我喜欢像Emacs一样可自我扩展的概念,这很容易扩展,但不能真正自我扩展。
我可以使用OCaml自行扩展程序吗? 我该怎么做?
我知道Emacs是如何工作的,它是一个很大的虚拟机,因此它可以解释代码并自行修改它的运行时环境,但有没有办法通过用户添加的模块为OCaml程序添加功能?或其他什么?
ps:如果我的项目听起来很基本但我是初学者,请不要嘲笑我!谢谢
答案 0 :(得分:5)
另一种解决方案可能是使用Ocaml dynamic loading设施,例如Dynlink模块。每个动态加载的共享模块可以例如将条目添加到某些全局哈希表映射字符串名称到函数(相同类型)等等。这个初始化 - 运行动态加载模块的顶层表达式 - 在其加载时发生(当您致电Dynlink.loadfile
时),有点像POSIX _init
的旧dlopen
函数
例如,您可以让程序在运行时发出一些Ocaml代码;将其汇编分成可加载的动态库using ocamlopt -shared
;然后Dynlink.loadfile
那个图书馆。该库的初始化部分将使用主程序中提供的一些适当的函数来注册闭包。
或者,在Ocaml中编写(或使用)某些虚拟机或解释器。
您也可以使用一些JIT库,例如Ollvm,并生成一些类似C的代码(可能在主程序的某些C粘合代码中使用dlopen
。)
但是Simon Shine answered, MetaOcaml 可能是更好的方法。
BTW,也许你想要一些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& C在C中执行类似的操作。 dlsym。我的GCC MELT正在进行that。另请参阅this。
注意:如果您喜欢元编程方法,请阅读J.Pitrat's blog和书籍。
答案 1 :(得分:2)
我可以使用OCaml自行扩展程序吗?
是的,你可以做一个自我扩展的翻译。
有没有办法通过用户添加的模块为OCaml程序添加功能?
是的,但是。 OCaml交互式提示是一个可扩展的程序。 MetaOCaml 是OCaml的多阶段编程扩展,可以在运行时间内对新机器代码进行增量编译。 [Wikipedia]除非您背驮其中一个,否则您正在寻找非 - 工程任务。
我该怎么做?
根据您想要做的具体内容,您还可以查看OCaml as Scheme或Scheme interpreter in Standard ML。那么你基本上必须构建一个read-eval-print循环来解析输入语言并相应地修改你的三元组。但不是直接使用OCaml。