Martin,
Appreciate your feedback. Some comments in-line (no need to reply).
Martin Jambon wrote:
> On Fri, 16 Mar 2007, Hugo Ferreira wrote:
>
snip...
>>
>> 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.
>
I would like to minor extensions, so this seems appropriate. I guess in
this case I can use ocamlp4 (save me the trouble of learning a new
syntax subset).
> * 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).
>
Ok. The original tutorial gave me this impression, so I will avoid this.
> * 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.
>
I guess the only time I will need this is for the "open" statements.
Your tutorial has an example (version number) of this so I may use it.
> * 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.
>
>
I do have the lexing and parsing ready for what I want at this point. In
fact all I want is to process a string (terms, term instances, horn
clauses and queries) expression and to generate a data structure
accordingly (terms and knowledge data source). From there it is simply a
matter of having Ocaml functions using this data. Ok, seems like I am
going in the right direction.
(Comment: I have used both ocamlyacc and menhir and menhir does indeed
give better error reports.)
>
>> 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.
>
Ok.
>
>> 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.
>
Ok. Your "default values for record fields" example has made this clear
to me.
> You should not use "let x = | ... |" if what you want to expand is the
> whole declaration rather than only the contents of | ... |.
>
I am only interested in the expanding the contents of |...|. In fact I
will have three basic groups of such cases. So I guess this is acceptable.
> * 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.
>
For now I will stick to the simpler convention of brackets (one per
group as stated above) for now. Seems easier to handle and my Vim editor
handles this ok.
> * do not allow unmatched brackets in your DSL.
>
Ok.
>
> 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.
>
I have done this as a pencil and paper exercise. I am now trying to do a
very simple example. See how it goes.
>
>
> 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
-~----------~----~----~----~------~----~------~--~---