A User-friendly Notation for Demo Users

-- A guide to the extended syntax used in the demo system --

by

Erwan De Bleeckere and Geraud Lacaze

August 1994


This HTML-document was created by Alf Beck Nielsen.
Last updated and validated Fri 20 Dec 1996 by krqlle@ruc.dk.

Contents

  1.   Overview
  2.   Three "brackets" Operators : \ , \\ and \\\
  3.   The User Syntax
  4.   Getting started this translating mode
  5.   What does the translating mode offer
  6.   Programming example
  7.  Appendix A

1.  Overview

When using demo, you write and use Prolog programs which are concerned with name terms, i.e., terms which represent names of phrases of the object language O.

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')]).

2.  Three "brackets" Operators : \ , \\ and \\\

The demo system provides the brackets described just before, but as such brackets do not exist in the standard computer character set :

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.

Indeed,  |¯ 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')]).

How these operators behave

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.

So, for instance, you have to type

    \\ p(a,X)     for     |¯ p(a,X) ¯|

and

    \\ p(?Z,X)    for     |¯ p( |_ Z _| ,X) ¯|

Note :  You would have better to get used to put a space between a "brackets" operator and its argument, otherwise it could be misunderstood on some occasions because of the Prolog interpreter behaviour. For instance, the following formula
             \\(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.

Some examples

In these examples, 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.
     \ 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

3.  The User Syntax

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.

Programs

They are normally written as prolog-lists of clauses.
     [c1,c2,c3]              programcons(c1,programcons(c2,
                                     programcons(c3,emptyprogram)))

     []                      emptyprogram
You 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)

Clauses

They are written in the normal ":-" syntax, e.g.
     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)

Literals

A literal is either an atom or a negated atom.
     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

Predicate symbols are written in the same way as in Prolog, i.e., as Prolog atom.

Note : Ssome Prolog atoms must not be used ("~" , ":-" , ",").

Formulas

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

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

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 anonymous variable

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

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.

Structures

     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

Function symbols are written in the same way as in Prolog, i.e., as Prolog atom.

Note : Some Prolog atoms must not be used ("~", ":-" , ",").

4.  Getting started this translating mode

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.


5.  What does the translating mode offer

As when using the Prolog interpreter, you can type in directives, read in programs and insert clauses at the terminal.

Typing in directives

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 terminal
     Y = \\ 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.

Reading in programs

To input a program from a file filename, just type the filename inside list brackets, thus :
     |  ?-  \  .
     \  ?- [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 :

Inserting clauses at the terminal

To enter clauses at the terminal, you must give the special directive :
     |  ?-  \  .
     \  ?- [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)

6.  Programming example

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

Appendix A

Here is the translation of the programming example (see section 6), 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) :- ! .