-- A guide to the extended syntax used in the demo system --
byErwan De Bleeckere and Geraud Lacaze
August 1994
\
, \\
and \\\
We have for instance that the Prolog term
atom(pred(p,2),[constant(a),variable('X')])is understood as the name of the O-atom
p(a,X)
.
This sort of representation is necessary in order to write the sort of meta-programming demo is dealing with but it is difficult both to read and write. So we have developed a syntax for dealing with such names and built a system which translate the terms written using this syntax into phrases of the object language O. This syntax is used for input and output from the terminal and also when reading programs from files.
In the literature it is costum to write some special brackets around the O-phrases to indicate the terms which define their names. Unfortunately these characters are not available in standard computer character set.
For example |¯p(a,X)
¯|
is an abbreviation for the longer
atom(predicate(p,2)[constant(a),variable('X')]).
It is also possible to parametrize such names by placing Prolog variables, i.e. meta-variables, in them in order to indicate yet unknown subphrases, when using reverse brackets.
For example |¯p(
|_
Z
_|
,X)
¯|
is translated into
atom(predicate(p,2),[Z,variable('X')]).
\
', '\\
' and '\\\
' declared
as a prefix operator, for "naming brackets".
?
', declared as a prefix operator too, for the reverse
brackets.
In addition to the usual "brackets" operator '\
', we have provided two extra
"brackets" operators '\\
' and '\\\
', in order to get rid of the ambiguity
inherent in the Prolog-like notation.
p(a,X)
¯|
can mean the name of an O-atom or the name of a O-term.
So it can be translated either into
atom(predicate(p,2),[constant(a),variable('X')])or into
structure(function(p,2),[constant(a),variable('X')]).
If '\ (..)
' can be understood as a program it is.
Otherwise, if it is of the form '\ (.. :- ..)
' it is understood as a
clause.
Otherwise there is a syntax error.
Anything prefixed by '\\
' is understood as a formula.
Anything prefixed by '\\\
' is understood as a term.
\\ p(a,X)
for
|¯
p(a,X)
¯|
\\ p(?Z,X)
for
|¯
p(
|_
Z
_|
,X)
¯|
\\(h(X),g(X))is understood by Prolog as a predicate, called '
\\
', with
two arguments, instead of
conjunction(atom(predicate(h,1),[variable('X')]), atom(predicate(g,1),[variable('X')])).When such event occurs, we display the following error message
{ERROR : please put a space between \\ and its argument in \\ (h(X),g(X))}.
Note : When you write a clause (inside "brackets"), surround it with parentheses.
Warning : If you use '\
', '\\
',
'\\\
' or '?
' outside the special mode, you then get something strange out
of it.
\ a module(a) \\ a atom(predicate(a,0),[]) \\\ a constant(a) \ [] emptyprogram \\ [] atom(predicate([],0),[]) \\\ [] constant([]) \ [a] programcons(clause(atom(predicate(a,0),[]),true), emptyprogram) \\ [a] atom(predicate('.',2),[constant(a),constant([])]) \\\ [a] structure(function('.',2),[constant(a), constant([])]) \ p(a) SYNTAX ERROR \\ p(a) atom(predicate(p,1),[constant(a)]) \\\ p(a) structure(function(p,1),[constant(a)])Note : When you make a mistake, writing
\ ?- X = \ p(a).an error message is then produced :
ERROR: bad syntax \ p(a). is not a program or a clause
The user syntax has to be used in the special brackets described before. By means of examples we indicate how it is translated into the internal ground representation.
All along the following description of this syntax, terms written using the user syntax are on the left side of the page and terms written in the internal representation are on the right side of the page.
[c1,c2,c3] programcons(c1,programcons(c2, programcons(c3,emptyprogram))) [] emptyprogramYou can also use metavariables.
[c1,c2| ?X] program(c1,program(c2,X))You can use a Prolog atom as the name of a module (which can be used where a program is expected) and can combine programs using the operator &. ((See the Users' Guide for how to declare such modules))
mymodule & [c1,c2| ?X] & yourmodule module(mymodule) & programcons(c1,programcons(c2,X)) & module(yourmodule)
For example :
?module(X) module(X)
head :- body clause(head,body)The head is a literal, the body a formula.
A clause which is a fact can be written in the Prolog way, just by writting its head, e.g.,
p(a) clause(atom(predicate(p,2), [constant(a)]),true)but only if it appears in a program!
If not, you have to write the body as well, e.g.
p(a) :- true clause(atom(predicate(p,2), [constant(a)]),true)
p(X,a) atom(predicate(p,2), [variable('X'),constant(a)]) ~p(X,a) not(atom(predicate(p,2), [variable('X'),constant(a)]))Note : The current version of demo do not support negation, the notation is provided for those who might want to modify the interpreter.
The lenght of the argument list is equal to the arity of the predicate. There can be predicates of arity 0.
rain atom(predicate(rain,0),[])
An other notation is provided :
p/2 - [a,X] atom(predicate(p,2), [variable('X'),constant(a)]).
Here follows some examples where it is useful.
?P - ?X atom(P,X) ?P/2 - ?X atom(predicate(P,2),X) p/?N - [a,b | ?Z] atom(predicate(p,N), [constant(a),constant(b)|Z])
Notice that when using this notation there is no control for consistency between the arity and lenght of the argument list.
Note : If for programming purposes you want to denote a predicate symbol out of context you have to write it preceded by '?', because we do not provide any special notation.For example :
?predicate(p,3) predicate(p,3)
Predicate symbols are written in the same way as in Prolog, i.e., as Prolog atom.
Note : Ssome Prolog atoms must not be used ("~" , ":-" , ",").A formula is either a literal, a conjunction (of other formulas) or the truth constants true or false.
f1,f2 conjunction(f1,f2) true true false false
Terms are either variables, constants or structures.
X variable('X') a constant(a) f(X,a) structure(function(f,2), [variable('X'),constant(a)])
Variables are written in the Prolog way, so any name which Prolog accepts as a variable is viewed as a variable.
X variable('X') _a variable('_a')Note : If for programming purposes you want to denote a variable with an unknown name, you have to write it preceded by '?', because we do not provide any special notation.
For example :
?variable(X) variable(X)
The user's syntax accepts the anonymous variable and treats it in a way so it behaves as Prolog's ditto. Each occurence of the anonymous variable is understood as a new variable not used anywhere else.
_ variable('anonymous117')
The following example shows how it behaves when used several times in an atom.
p(_,_) atom(predicate(p,2), [variable('anonymous118'), variable('anonymous119')])
Constants are written in the Prolog way, so any name which Prolog accepts as a constant is viewed as a constant.
a constant(a) 7 constant(7) 'X' constant('X')Note : If for programming purposes you want to denote a constant with an unknown name, you have to write with a '?', because we do not provide any special notation.
For example :
?constant(X) constant(X)
Note : Structures and function names are analogous to atoms and predicate names.
f(X,a) structure(function(f,2), [variable('X'), constant(a)])The lenght of the argument list is equal to the arity of the function. Note : There cannot be function of arity 0, for it is then a constant.
An other notation is provided :
f/2 - [a,X] structure(function(f,2), [variable('X'), constant(a)]).
Here follows some examples where it is useful.
?F - ?X structure(F,X) ?F/2 - ?X structure(function(F,2),X) f/?N - [a,b | ?Z] structure(function(f,N), [constant(a), constant(b) | Z])Notice that when using this notation there is no control for consistency between the arity and lenght of the argument list. Note : If for programming purposes you want to denote a function symbol out of context you have to write it preceded by '?', because we do not provide any special notation.
For example :
?function(p,3) function(p,3)
Function symbols are written in the same way as in Prolog, i.e., as Prolog atom.
Note : Some Prolog atoms must not be used ("~", ":-" , ",").Normally you will start the whole Demo system using the 'demoSYSTEM' or 'demoSYSTEMcompiled' files.
Here we illustrate how you can start it manually.
At first, you have to load all the relevant files which implement the user syntax, by typing :
| ?- use_module(library(lists)) , [nameof,nameofGo,nameofBack,namingtools,translator] .
You then can use the naming relation facilities, so you go on typing :
| ?- \ . \ ?- [constraints,moduleManager,metaUtilities,demo] .Notice the space between \ and the period. Note : During the execution of this directive you will be asked things like
do you want constraints_trans to be deleted ? (y/n)(As well for moduleManager, metaUtilities, demo)
It is up to you, whether you want to look at the translation
of the source files or not.
Notice that to reply 'yes', you just need to type RET.
The whole demo system is loaded and ready for use.
Note : the constraints, moduleManager ,metaUtilities, and demo files have been written using the user syntax (see description in section 2), so they only can be loaded under the translating mode.As shown above (when loading the system), you just have to type '\ .' followed by RET in order to start the translating mode. The new prompt '\ ?-' appears and you then can type in your directive. Note that you only stay in the translating mode for once! Each time you want to go in again you have to type '\ .' followed by RET.
As when using the Prolog interpreter, you can type in directives, read in programs and insert clauses at the terminal.
You can type queries at the terminal and include commands in your files. The syntax of queries and commands is Prolog-like, with the brackets and reverse brackets extra.
Here is a little example of a query and answer from the system:| ?- \ . \ ?- demo(\ [ (grass_is_wet :- rained_last_night), (grass_is_wet :- sprinkler_was_on) ] & [?WHY] , \\ grass_is_wet). WHY = \ (rained_last_night :- true) ?if you then type RET
yes
The main difference between the demo interpreter and the Prolog interpreter is the outcome display. Indeed, any answer given by the demo interpreter (when you have made a query under the translating mode) is translated "back" before being displayed, in order to make it the more readable as possible.
For instance, you will see displayed on the terminalY = \\ p(a,X)instead of
Y = atom(predicate(p,2),[constant(a),variable('X')]) .Note : If the answer contains either anonymous variables or internal Prolog variables you will see on screen things like _188 rather than _ or _A, because Prolog do not provide the facilities to rename variables in a consistent way.
Like with the usual Prolog interpreter, if a query contains variables, their final values are displayed on the terminal in the form shown above (except for anonymous variables).
You then can ask the system for backtracking in order to find alternative solutions, when typing ; followed by RET. Otherwise just type RET to terminate the query.
| ?- \ . \ ?- [filename].This instructs the interpreter to read the file, to translate it and to consult the translated file.
The name of this translated file is filename_trans, and you have to decide if it has to be deleted or not after beeing consulted by the interpreter answering the question displayed at the terminal, e.g.
Do you want filename_trans to be deleted ? (y/n)
Note: This directive can be any list of filename. All the translated files are then consulted.
Warning: If errors occur when Prolog is consulting a file, the line numbers and variable names printed at screen are wrong, because they are dealing with the translated file. So you would have better to look at first in the translated file to situate the error.
The following predicates behave in a similar way :
| ?- \ . \ ?- [user]. \ |
The new prompt '\ |' appears, and you can type your clauses or directives. To return to interpreter top level, type ^D.
As when reading in programs you will be asked :
Do you want user_trans to be deleted ? (y/n)
The following example is a program which counts the constants that appear in a program written in the object language O. The main interest is that it shows how to program using the user syntax facilities.
Here is this program :count_const_in_program(\ [], 0) :- ! . count_const_in_program(\ [? C | ? P], N) :- ! , count_const_in_clause(C, N1), count_const_in_program(P, N2), N is (N1+N2). count_const_in_clause(\ (? H :- ? B), N) :- ! , count_const_in_literal(H, N1), count_const_in_formula(B, N2), N is (N1+N2). % atom count_const_in_literal(\\ (? _ - ? Args), N) :- count_const_in_list(Args, N). % conjunction count_const_in_formula(\\ (? A, ? B), N) :- ! , count_const_in_formula(A, N1), count_const_in_formula(B, N2), N is (N1+N2). % atom count_const_in_formula(\\ (? _ - ? Args), N) :- ! , count_const_in_list(Args, N). count_const_in_formula(true, 0) :- ! . count_const_in_formula(false, 0) :- ! . count_const_in_list([constant(_)| L], N) :- ! , count_const_in_list(L, N1), N is N1+1. % structure count_const_in_list([\\\ (? _ - ? Args) | L], N) :- ! , count_const_in_list(L, N1), count_const_in_list(Args, N2), N is (N1+N2). % variables count_const_in_list([variable(_) | L], N) :- ! , count_const_in_list(L, N). count_const_in_list([], 0) :- ! .
You go into the special mode to load the program (let's call it 'count'), e.g.,
| ?- \ . \ ?- [count].Note : You can see the translation 'count_trans' of count in the appendix A. ( at the end of this chapter)
And then make some test :
| ?- \ . \ ?- count_const_in_program(\ [ ( p(a,X) :- g(b,X,f(c,f1(e))) ), ( p(b,X) :- h(a,X), j(X,c) ) ] , Nb_const ). Nb_const = 7 ? yes
count_trans
:
count_const_in_program(emptyprogram, 0) :- ! . count_const_in_program(programcons(A,B), C) :- ! , count_const_in_clause(A, D), count_const_in_program(B, E), C is (D+E). count_const_in_clause(clause(A,B), C) :- ! , count_const_in_literal(A, D), count_const_in_formula(B, E), C is (D+E). count_const_in_literal(atom(_,A), B) :- count_const_in_list(A, B). count_const_in_formula(conjunction(A,B), C) :- ! , count_const_in_formula(A, D), count_const_in_formula(B, E), C is (D+E). count_const_in_formula(atom(_,A), B) :- ! , count_const_in_list(A, B). count_const_in_formula(true, 0) :- ! . count_const_in_formula(false, 0) :- ! . count_const_in_list([constant(_)| A], B) :- ! , count_const_in_list(A, C), B is C+1. count_const_in_list([structure(_,A) | B], C) :- ! , count_const_in_list(B, D), count_const_in_list(A, E), C is (D+E). count_const_in_list([variable(_) | A], B) :- ! , count_const_in_list(A, B). count_const_in_list([], 0) :- ! .