OCaml,在Emacs上扩展了一个程序

OCaml,在Emacs上扩展了一个程序,ocaml,Ocaml,我爱OCaml,我在等待我的真实世界OCaml副本! 我是一个OCaml初学者,只知道函数部分,有一点命令性,但不太了解模块、函子、对象等 对于一个翻译项目,我做了一个类似于emacs的新手评估。我保留了一个三元组列表,其中包含一个命令名绑定列表,作为字符串,一个用于描述的字符串,以及要调用的ocaml函数。主循环只需在列表中查找匹配项并调用函数 然后添加新的函数性就很简单了,只需编写一个函数并在列表中添加一个条目 我喜欢像Emacs一样可以自我扩展的概念,这很容易扩展,但不是真正的自我扩展 我

我爱OCaml,我在等待我的真实世界OCaml副本! 我是一个OCaml初学者,只知道函数部分,有一点命令性,但不太了解模块、函子、对象等

对于一个翻译项目,我做了一个类似于emacs的新手评估。我保留了一个三元组列表,其中包含一个命令名绑定列表,作为字符串,一个用于描述的字符串,以及要调用的ocaml函数。主循环只需在列表中查找匹配项并调用函数

然后添加新的函数性就很简单了,只需编写一个函数并在列表中添加一个条目

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

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

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

ps:如果你觉得我的项目很基本,不要嘲笑我,但我是个初学者

多谢各位

我可以用OCaml使程序自扩展吗

是的,你可以做一个自我扩展的解释器

有没有一种方法可以通过用户添加的模块向OCaml程序添加功能性

是的,但是。OCaml交互式提示符就是这样一个可扩展的程序。是OCaml的多阶段编程扩展,支持在运行时增量编译新的机器代码。[维基百科]除非你背负其中一项,否则你将面临一项非琐碎的工程任务

我该怎么做


根据你想做什么,你也可以看看或。然后,您基本上必须构建一个read-eval-print循环来解析输入语言并相应地修改三元组。但不能直接使用OCaml。

另一种解决方案可能是使用OCaml设施,例如模块。例如,每个动态加载的共享模块可以向某些全局哈希表添加条目,将字符串名称映射到函数(相同类型),等等。。。动态加载模块的初始化(运行其顶级表达式)发生在加载时(当您调用
Dynlink.loadfile
时),有点像POSIX
dlopen
的旧
\u init
函数

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

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

您还可以使用一些JIT库,例如,生成一些类似C的代码(可能在主程序的一些C粘合代码中使用
dlopen

但作为一个例子,MetaOcaml可能是一种更好的方法

顺便说一句,也许您想要一些常见的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.add_name_fun "foo" (fun x -> x+3);;
您的
prog.mli
将包含:

  val : add_name_fun : string -> (int -> int) -> unit;;
您的
plugin.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.add_name_fun "foo" (fun x -> x+3);;
但是我没有测试代码

另外,在POSIX系统上,您可以使用&在C中执行类似的操作。我的GCC正在做。另见


注:如果你喜欢元编程方法,请阅读和阅读相关书籍。

谢谢你,我正在考虑一种Dynlink方法的实现,如果实现得好,它可能会起作用,就像你说的那样,它可能不安全。。。但这是一个很好的选择,我也要!此外,BER MetaOCaml非常吸引人!我更喜欢深入研究OCaml,因为我在大学里学过它,我想“掌握”它。(程序员永远不会掌握一门语言…),但如果有时间,我一定会看看Common Lisp。这个问题的目的是为了学习Xmonad窗口管理器的分支(用Haskell编写),这次是用OCaml,使用wayland。用户可以在运行时添加一些用OCaml代码编写的功能(如Xmonad中的Haskell),而无需像emacs那样重新加载所有配置“加载的编译单元中的所有顶级表达式都将被计算。没有提供任何设施来访问该单元定义的值名称。因此,装置必须向主程序注册其入口点,例如通过修改功能表。“它是如何工作的?当我调用loadfile时,它运行ocaml代码并修改函数条目?如果有一些非声明性代码,那么它是否执行?链接的代码可以访问加载器的变量吗?如果是这样,我可以有一个函数列表,并在列表中添加加载的函数。是的。您可能需要一个从字符串名到函数名的哈希表,它会变得更清晰。。。这是一个关于加载插件的好教程。所以我可以有一个插件接口,加载插件模块,并将它们存储在一个关联列表中,其中包含来自文件名的散列。我说的对吗?MetaOcaml似乎就是我要找的。但我不确定,我不想让用户在运行时将其代码添加到程序中。代码将从文件中读取,当然是作为字符串,我可以用MetaOcaml将字符串转换为代码吗?就像一个eval函数一样,MetaOcaml似乎不是这样工作的,仍然有一个解决方案可以编写内部解释器,但它需要函数性。有人使用ocaml顶级库()编写了一个eval函数但它在实际版本的ocaml上不起作用,它使用的文件toplevellib.cma还不存在,太糟糕了。。。