I am writing a program which parses scripts written in some made-up language and does some computations using that script. This language has a particular construct which is used to call external OCaml functions of the type 'a -> bool
. So, in the middle of the language we may have
blah blah function (foo 45) blah blah
and I'd like the pars开发者_C百科er to use a constructor such as
OCamlFunction of ('a -> bool) * 'a
to parse that bit as the value
OCamlFunction (foo,45)
where 'foo' is a function that the user will have to provide in a separate .ml file and which the parser doesn't know beforehand; only the name of the OCaml file where "foo" is defined is passed to the parser at runtime. So, I need to define a function of type string->('a->bool)
which takes the name of some function and returns that function.
My questions are:
(1) I'm assuming that the dynamic loading of code should use DynLink.loadfile. Is this the way to go?
(2) How do I get access to the function "foo" from the knowledge of its identifier? (Will this lead me to camlp5?)
You cannot, directly, load a function by name, as OCaml does not have that kind of support and the loadfile
function just runs the code, it does not provide access to names.
You need to support some kind of function registration API in your main program that is used by the loaded code. So the loaded code would do something like
ParserEngine.register_function "foo" foo_impl
You could use Camlp{4,5} to automate this boilerplate code generation, or you could have a register_functions
call that takes an association list to minimize it.
register_functions
would then store the functions in some internal structure like a hash table or mutable association list, ready for your parser code to access.
Another solution would be to place the whole script in a quotation, and put each ocaml value inside in an antiquotation. This can be done with Camlp4 for example, but has a slight syntactic cost (<<
>>
around your code, $
$
around OCaml values). The parsing of the script would then run at compile-time, so the OCaml typer itself could check that the OCaml values you refer too are well defined. In addition, you get finer type control.
精彩评论