4

I love OCaml, I'm waiting for my copy of Real World OCaml ! I am a beginner OCaml programmer, just know the functionnal part, a little imperative, but not much about modules, functors, objects, etc...

For sort of an interpreter project, I made sort of a newbie emacs-like evaluation. I keep a list of triplet containing a list of command name bindings as strings, a string for the description, and the ocaml function to call. The main loop just look for a matching entry in the list and call the function.

Then it was really simple to add new functionnalities, you just write a function and put an entry in the list.

I like the concept of being self-extensible like Emacs, this was easily extendable, but not really self extendable.

Could I make a program self extensible with OCaml ? How would I do that ?

I know how Emacs works, it is a big virtual machine so it interpret code and modify it's runtime environment by itself, but is there a way to add functionnalities to an OCaml program with user added modules ? or something else ?

ps : Don't laugh at me if my project sounds basic to you but I'm a beginner !

Thank you

Drew
  • 29,895
  • 7
  • 74
  • 104

2 Answers2

5

Another solution might be to use Ocaml dynamic loading facilities, e.g. the Dynlink module. Each dynamically loaded shared module could for example add entries to some global hash table mapping string names to functions (of the same type), etc... This initialization -running its top level expressions- of the dynamically loaded module happens at its loading time (when you call Dynlink.loadfile), a bit like the old _init function for POSIX dlopen

For example, you could have your program emit some Ocaml code at runtime; fork a compilation of it into a loadable dynamic library using ocamlopt -shared ; then Dynlink.loadfile that library. The initializing portion of that library would register closures using some appropriate function provided in your main program.

Alternatively, write (or use) some virtual machine or interpreter in Ocaml.

You might also use some JIT library, e.g. Ollvm, and generate some C-like code (perhaps using dlopen in some C glue code of the main program).

But as Simon Shine answered, MetaOcaml could be a better way.

BTW, perhaps you want some Common Lisp implementation?


Example:

(untested code! some details could be wrong)

Your main program prog.ml would contain

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);;

Your prog.mli would contain:

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

Your plugin.ml would contain

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

But I did not test the code.

PS. On POSIX systems, you can do similar things in C with dlopen & dlsym. My GCC MELT is doing that. See also this.

NB: If you are fond of meta-programming approaches, read J.Pitrat's blog and books.

Community
  • 1
  • 1
Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • Thank, you, I'm thinking about an implementation of the Dynlink way which might work if well implemented, like you said it can be unsafe... But this is a good alternative, I'll take it too ! Also, BER MetaOCaml is very attractive ! I prefer to go deep into OCaml since I learned it at University and I'd like to "master" it. (a programmer never master a language...), but I will certainly take a look at Common Lisp when I would have time to. – Nicolas Scotto Di Perto Jan 08 '16 at 12:18
  • The purpose of that question is the project of a fork of Xmonad window manager (written in Haskell), this time in OCaml, using wayland, for a learning purpose. The user could add some features written in OCaml code (like Haskell in Xmonad) at runtime without reloading all configuration, like emacs does. – Nicolas Scotto Di Perto Jan 08 '16 at 12:19
  • In Dynlink function `loadfile` : " All toplevel expressions in the loaded compilation units are evaluated. No facilities are provided to access value names defined by the unit. Therefore, the unit must register itself its entry points with the main program, e.g. by modifying tables of functions." How does it works ? When I call loadfile it runs the ocaml code and modify functions entries ? If there are some not declarative code, is it executed then ? Can the linked code access to variables of the loader ? If so, I could have a list of functions and add loaded functions in that list. – Nicolas Scotto Di Perto Jan 08 '16 at 22:36
  • Yes. You probably might want an hash table from string names to functions – Basile Starynkevitch Jan 09 '16 at 06:32
  • Ok, it becomes clearer... http://zderadicka.eu/plugins-in-ocaml-with-dynlink-library/ is a good tutorial about loading plugins. So I could have a plugin interface, load plugins module and store them in an association list with a hash from the filename. Am I right ? – Nicolas Scotto Di Perto Jan 09 '16 at 09:56
  • Not an hash from filenames, but from names of values – Basile Starynkevitch Jan 09 '16 at 12:08
  • Do you means functions names ? I really don't see how to get these since the whole file is loaded in an opaque manner. Maybe I don't understand how it works, I have read the documentation but I don't fully understand because English is not my language. – Nicolas Scotto Di Perto Jan 09 '16 at 18:32
  • No, arbitrary names (or other keys) which you would associate to some values. – Basile Starynkevitch Jan 09 '16 at 21:26
  • Ok thanks, finally your answer is the good so I change that. @Basile Starynkevitch sorry, but thanks to you I have discovered MetaOCaml and that's really cool ! – Nicolas Scotto Di Perto Jan 09 '16 at 21:39
2

Could I make a program self extendable with OCaml?

Yes, you could make a self-extensible interpreter.

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

Yes, but. The OCaml interactive prompt is such an extensible program. MetaOCaml is a multi-stage programming extension of OCaml enabling incremental compiling of new machine code during runtime. [Wikipedia] Unless you piggy-back on one of these, you are looking at a non-trivial engineering task.

How would I do that?

Depending on exactly what it is you want to do, you could also look at OCaml as Scheme or Scheme interpreter in Standard ML. Then you would basically have to build a read-eval-print loop that parses an input language and modifies your three-tuple accordingly. But not with OCaml directly.

sshine
  • 15,635
  • 1
  • 41
  • 66
  • MetaOcaml seems to be what I am looking for. But I'm not sure about it, I wan't to let the user add it's code to the program at runtime. Code would be read from a file, certainly as string, can I convert string to code with MetaOcaml ? – Nicolas Scotto Di Perto Jan 08 '16 at 16:52
  • Like an eval function, it seems that MetaOCaml doesn't work like that, there's still the solution to write an internal interpreter but it would like of functionnality. – Nicolas Scotto Di Perto Jan 08 '16 at 21:56
  • Someone have written an eval function using ocaml toplevel library (https://thelackthereof.org/OCaml_Eval) but it doesn't work on actual version of ocaml, it uses the file toplevellib.cma which doesn't exists yet, too bad... – Nicolas Scotto Di Perto Jan 08 '16 at 23:33