On Fri, 16 Mar 2007, Hugo Ferreira wrote:
>
> Hi,
>
> I have the need to use some logical programming functionality within my
> application. I would like to embed this into my Ocaml code as a domain
> specific language. I am contemplating the use of Camlp4 for this. My
> main concern is the effort this will require. I am not concerned so much
> in the implementation effort of parsing and processing the logical part
> of the code (cannot escape that) but in evaluating the work required to
> use Camlp4.
>
> Below I have some examples of what I am considering. Note that I use "|"
> as a delimiting token to identify the embedded language. Within these
> delimiters I aim to use menhir/ocamllex/ocamlyacc to generate compile
> time data-structures and then output calls to the logical sub-system.
> The calls will effectively perform the logical evaluation of horn
> clauses.
>
> My questions are:
>
> 1. Is this feasible?
I think the real question is "how hard is it?".
Camlp4 provides different things and you don't have to use all its
arsenal.
Let me give you my personal opinion on the difficulty of different things:
* emitting OCaml code from an OCaml program: easy; if you don't want to
use the revised syntax, you may want to try ocamlp4, which I haven't.
* writing a syntax extension that does only inline substitution: very
convenient using EXTEND statements.
* writing a syntax extension by defining a quotation expander: difficult
if you want to handle error locations properly. This is however convenient
if you really need a lexer which is different from the OCaml one. The
other solution is to use strings, preceded by some keyword. Quotations can
only expand to a single expression or to a single pattern (no toplevel
declaration like types or groups of declarations).
* writing a syntax extension that requires some code to be inserted in
other places of the program: tricky and somewhat dirty but feasible using
the declare_once module from the regexp-pp package. I would not recommend
doing this if you want your implementation to remain clear and simple.
* writing a grammar for a DSL that is not an extension of the OCaml
grammar: relatively easy if your grammar is LL(1) and once you figure out
how to plug the lexer in and other annoying details. You could use menhir
or ocamlyacc too. Using ocamlyacc may be difficult and it doesn't produce
useful error messages automatically. I don't know about menhir, but it's
supposed to be better than ocamlyacc.
> 2. Does it require much effort (any one venture an estimate)?
If you are comfortable with functional programming in OCaml already, and
if you like adventure, then you could obtain some good results within a
few days. But there are pitfalls that you should avoid. See below for an
incomplete list.
> 3. Is the syntax I show acceptable (any suggestions)?
For an easy integration into OCaml, here are a few rules of thumb:
* make the embedded language well-delimited from the rest. It means that
all the information must be contained in the first two tokens. For
special type definitions, I like to use a keyword (which is actually a
LIDENT) just after the "type" keyword:
type special t = ...
For value definitions:
let special f = ...
Starting with an existing keyword lets you define your special keyword as
a LIDENT (lowercase identifier) and use it as a regular identifier
elsewhere. It helps not breaking existing code.
You should not use "let x = | ... |" if what you want to expand is the
whole declaration rather than only the contents of | ... |.
* text editor modes are not ready for special syntax extensions and it
results in bad automatic indentation. Using parentheses around the parts
written in the special syntax helps when it's possible. Otherwise, you may
want to choose a convention that forces the use of brackets ((), [] or {})
combined with another symbol. Make sure other popular camlp4 extensions do
not use the same convention (hard) or use this in addition to a preceding
keyword (easy and safer):
let special {| ... |}
where ... can be anything using existing ocaml keywords with your own
rules, as long as brackets in your DSL are matched.
* do not allow unmatched brackets in your DSL.
I don't know what your example should be expanded into so I can't tell
you exactly what's wrong and what's right. A good startpoint for you would
be to translate manually a complete example into plain OCaml.
Martin
--
Martin Jambon
http://martin.jambon.free.fr
> --------------------------------------------
> Examples
> --------------------------------------------
>
>
> (* Example of a query *)
> let prog = | f(a,b).
> f(b,c).
>
> g(X,Y):- f(X,Z), f(Z,Y) | in
> let result = prog:| g(X,Y), g(X,X) | (* conjunction, not a tuple *)
> in
> result
>
>
> (* Example of unification *)
> let prog = | | in
> let inst1 = prog:|| h(a,X,Y,d) || in
> let inst2 = prog:|| h(X,b,c,Y) || in
> let result1 = inst1 .= inst2 (* [EMAIL PROTECTED],
> =:= *)
> in
> result (* returns the unified instance and the mgu *)
>
> (* Example of list of terms *)
> let prog = | | in (* empty *)
> let inst1 = prog:|[ h(a,X,Y,d); i(X,b) ]| in
> let inst2 = prog:|[ h(X,b,c,Y); i(a,X) ]| in
> (* tuples use "|(", arrays "|[|" *)
> let rec loop l1 l2 r =
> match l with
> | h1::t1, h2::l2 -> loop ( h1 .= h2 )::r
> | r
> in
> loop inst1 inst2 []
>
>
> (* Instantiating terms *)
> let prog = | | in
> let expr1 = || [h(a,X,Y,d), i(X,b)] || in
> let expr2 = || [h(X,b,c,Y), i(a,X)] || in
> let inst1 = prog:| expr1 | in
> let inst2 = prog:| expr2 | in
> let result = inst1 .= inst2
> in
> result
>
>
>
> (* Backtracking *)
> let p0 = | | in
> let expr1 = || h(a,X,Y,d) || in
> let expr2 = || h(X,b,c,Y) || in
> let expr3 = || h(X,Y,c,d) || in
> let (p0,i1) = p0:| expr1 | in(* uses the result of previous
> processing *)
> let (p1,i2) = p0:| expr2 | in(* uses the result of previous
> processing *)
> let result = inst1 .= inst2 in
> let result = if .! result then (* try another option *)
> let inst1 = p0:| expr1 | in
> let inst2 = p1:| expr1 | in
> in
> result
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"ocaml-developer" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at
http://groups.google.com/group/ocaml-developer?hl=en
For other OCaml forums, see http://caml.inria.fr/resources/forums.en.html
-~----------~----~----~----~------~----~------~--~---