
















                          THE PARALLEL PARLOG USER MANUAL



                    Jim Crammond, Andrew Davison, Alastair Burt,
                          Matthew Huntbach and Melissa Lam

                                    Parlog Group
                              Department of Computing
                              Imperial College, London
                                  9th October 1989

                                      Revised
                                   14th June 1990





































                                                             User Manual

            _1.  _I_N_T_R_O_D_U_C_T_I_O_N

            The first part of this document is a user manual in tutorial
            form,  and  may  be  read while trying out the examples at a
            terminal. The second part is a reference  manual,  and  con-
            tains  a  definition of Parallel Parlog and documentation on
            system predicates.  The  reader  is  assumed  to  have  some
            knowledge of Parlog and Unix.


            _2.  _A_B_O_U_T _P_A_R_A_L_L_E_L _P_A_R_L_O_G

            Parallel Parlog is an implementation of  Parlog  for  shared
            memory multiprocessor machines. Versions currently exist for
            the Sequent Balance and Symmetry, Encore Multimax and  Alli-
            ant  FX/8. Uniprocessor versions are also available for Sun3
            and Sun4 workstations. The syntax is standard Parlog and  is
            compatible  with  the SPM [Foster et al. 1986] and MacParlog
            [Conlon and Gregory 1989]

            The language is as defined in [Gregory 1987], except for the
            _n_o_n_f_l_a_t  _g_u_a_r_d  _r_e_s_t_r_i_c_t_i_o_n  [see 9. Guard Safety Considera-
            tions], the restricted form of  the  metacall  [see  section
            6.2.  in  the  Reference  Manual], and the introduction of a
            simple module scheme [see 8. Modules].

            This manual describes the second  release  of  the  Parallel
            Parlog system, _V_1._4, which contains a number of improvements
            over the first release _V_1._0.  Any program  compiled  on  the
            first release will need to be recompiled in order to be exe-
            cuted on the new release of the system.

            The main feature of the second release of the Parallel  Par-
            log system is a new memory management system that allows the
            different data areas within the emulator [Crammond 1990]  to
            dynamically  expand  (and contract) as required. On machines
            that allow shared memory to  be  expanded  during  execution
            this  makes the new Parlog system somewhat more robust, par-
            ticularly when using many processors, and also more economi-
            cal  when executing small programs, particularly on a single
            processor.


            _3.  _E_N_T_E_R_I_N_G _A_N_D _E_X_I_T_I_N_G _T_H_E _P_A_R_A_L_L_E_L _P_A_R_L_O_G _S_Y_S_T_E_M

            The system can be entered  by  typing  the  command  parlog.
            This  command  has  one  option -n_x which specifies that the
            system should execute on _x processors.  On startup, the Par-
            log system displays the following message on the screen:


                Parallel Parlog V1.4 - 12 Jun 1990
                Copyright (C) 1990, Parlog Group, Imperial College

                | ?-



                                         1





                                                             User Manual

            To exit Parlog, type the  end  of  file  character  (usually
            control-D) or the command halt.


            _4.  _R_U_N_N_I_N_G _Q_U_E_R_I_E_S

            In response to the | ?-  prompt the user may enter any  con-
            junction  of  Parlog  calls terminated by a full stop.  This
            conjunction is evaluated as a query, and if it is successful
            the  bindings for the query are printed out and the word yes
            appears.   Bindings  are  not  printed  for  void  variables
            (denoted  by an underscore). If the query fails then this is
            indicated with no.  This is  illustrated  by  the  following
            simple example:


                | ?- X is 1 + 2.
                 X = 3

                yes
                | ?- _ is 1 + 2.

                yes
                | ?- X is 1 + 2, X is 2 + 2.

                no
                | ?- halt.
                ncalls/utime = 461 / 0.02 = 23050.0 RPS


            The evaluation of a query can be interrupted by  typing  the
            interrupt character (usually control-C). This should produce
            the prompt "Parlog interruption ? ".  By typing y<return> to
            this  prompt,  the  execution  of the query will be aborted;
            typing n<return> will cause the execution to resume.

            Note: if the interrupt prompt does not appear on the  screen
            within  a few seconds of typing an interrupt then the system
            has hung in some way. The only rescue from this situation is
            to type the quit character (usually control-\).


            _5.  _L_O_A_D_I_N_G _A_N_D _C_O_M_P_I_L_I_N_G

            Users may define their own  Parallel  Parlog  predicates  by
            placing  them  in a text file. The correct syntax for predi-
            cates is defined in the Reference Manual  [section  1].   To
            make  them  available  within  the system, a Parallel Parlog
            object code file should be generated by using the  compile/1
            predicate,  and  this  should then be loaded with the load/1
            predicate.

            It is usual for the Parlog text file to have a  .par  exten-
            sion  and the object file an .o extension, as in the follow-
            ing example, but this is optional  [see  section  5  in  the
            Reference Manual].


                                         2





                                                             User Manual

                tutorial% cat tst.par

                mode merge(?,?,^).
                merge([A|As],Bs,[A|Cs])<-
                    merge(As,Bs,Cs).
                merge(As,[B|Bs],[B|Cs])<-
                    merge(As,Bs,Cs).
                merge([],Bs,Bs).
                merge(As,[],As).

                tutorial% parlog
                Parallel Parlog V1.4 - 12 Jun 1990
                Copyright (C) 1990, Parlog Group, Imperial College

                | ?- merge([1,2],[3,4],X).
                [Warning: the procedure merge/3 is undefined]

                no
                | ?- compile(tst) & load(tst).
                [loading compiler]
                Compiling file tst.par
                merge / 3
                File tst compiled.

                yes
                | ?- merge([1,2],[3,4],X).
                 X = [1,2,3,4]

                yes
                | ?- halt.

                ncalls/utime = 5269 / 2.18 = 2416.97 RPS
                tutorial% ls
                tst.o           tst.par
                tutorial%


            Terms in the source file with the  form  <-  _c_o_n_j_u_n_c_t_i_o_n-_o_f-
            _g_o_a_l_s.  are treated as commands, which are executed automat-
            ically as the object file is loaded.


            _6.  _T_R_A_C_I_N_G

            The Parallel  Parlog  system  supports  rudimentary  tracing
            facilities, through the use of _s_p_y_p_o_i_n_t_s.  A spypoint may be
            placed  on  a   predicate   using   the   spy/1   predicate.
            Thereafter,  each time the predicate is called, the goal and
            the current state of  its  arguments  is  displayed  on  the
            screen  preceded  by  a  Call:  message.  The  user  is then
            prompted, and four kinds of response are possible.

            1)  When the user types <return>, the traced  call  is  exe-
            cuted  and  a further message is displayed on termination of
            the call. This message is either Exit: or Fail:, followed by
            the goal and its arguments.


                                         3





                                                             User Manual

            2)  Typing n<newline> will cause the spypoint to be  removed
            before executing the call.  Thereafter, further calls to the
            predicate will not be traced (but existing calls will  still
            be  traced  when  they  terminate).   Spypoints  can also be
            removed with the nospy/1 predicate.

            3)  Typing a<newline> will abort the call.

            4)  Typing c goal.<newline> will cause goal to be  executed.
            This  can  be  useful  for  setting further spypoints before
            proceeding with this call. Once goal has completed, the user
            is prompted again for action on this call.


                | ?- spy(merge/3).

                yes
                | ?- merge([1,2],[],[1,3]).
                Call: merge([1,2],[],[1,3]) ?
                Call: merge([2],[],[3]) ?
                Fail: merge([2],[],[3]) ?
                Fail: merge([1,2],[],[1,3]) ?

                no
                | ?- merge([1,2],[],X).
                Call: merge([1,2],[],_3122) ?
                Call: merge([2],[],_3220) ?
                Call: merge([],[],_3274) ?
                Exit: merge([],[],[]) ?
                Exit: merge([2],[],[2]) ?
                Exit: merge([1,2],[],[1,2]) ?
                 X = [1,2]

                yes
                | ?- merge([1,2],[],X).
                Call: merge([1,2],[],_3894) ? a

                no
                | ?- merge([1,2],[],X).
                Call: merge([1,2],[],_3589) ? n
                 X = [1,2]

                yes
                | ?-


            Notes:

            1.   The emulator will continue to  execute  runnable  goals
                 while  waiting  for  the  prompt to a traced call; thus
                 potentially altering the scheduling behaviour, particu-
                 larly on one processor.

                 A consequence of this is that parallel invocations of a
                 spied  predicate  result  in  multiple  Call:  messages
                 appearing, each requiring a response.  This  is  rather


                                         4





                                                             User Manual

                 unsightly at times.


            2.   A common fault that causes programs that  work  on  one
                 processor   to  fail  on  multiple  processors  is  the
                 incorrect use of var(X) in a guard. Such  a  guard  may
                 succeed unexpectedly because it runs in parallel with a
                 goal that eventually binds X.  Remember, var(X) is time
                 dependent  and  must be used with care in parallel pro-
                 grams.


            _7.  _E_R_R_O_R _M_E_S_S_A_G_E_S

            There are four sorts of error messages which  the  user  may
            encounter :


            _7._1.  _B_u_i_l_t_i_n _E_r_r_o_r_s

            When the system predicates are given  incorrect  input  they
            generate messages of the form :

            [Error:  _m_e_s_s_a_g_e: _b_u_i_l_t_i_n _n_a_m_e _a_n_d _a_r_g_u_m_e_n_t_s]


            _7._2.  _S_y_n_t_a_x _E_r_r_o_r_s

            The read predicates [see section  6.3.3.  of  the  Reference
            Manual]  return error messages when they are used with input
            that does not conform to Parlog syntax.  Since the  compiler
            and  the top level query evaluator use these predicates, the
            user will find the same messages displayed here.  The format
            is:

            **Syntax Error: _o_f_f_e_n_d_i_n_g _t_e_r_m

            The offending term is listed, and the place where the  error
            occurred is marked by the word <<here>>.


            _7._3.  _C_o_m_p_i_l_e_r _E_r_r_o_r_s

            The compiler may generate the following messages :

            **Syntax Error: - see above.

            **Mode Declaration Error:  _M_o_d_e - The mode is  wrongly  for-
            matted; usually a ^ or ? is missing.

            **Compiler Error - Name/Arity mismatch:   _N_a_m_e/_A_r_i_t_y  -  The
            clauses  grouped  together as one procedure with the sequen-
            tial search operator (;) do not  share  the  same  name  and
            arity.

            **Compiler Error: _N_a_m_e/_A_r_i_t_y - Any other compiler error.


                                         5





                                                             User Manual

            After processing the source file, a summary of  all  of  the
            error  messages  is  displayed.  This  is illustrated by the
            example session given below, which captures a  syntax  error
            in the first predicate of the _k_k_q_u_e_e_n._p_a_r file.


                tutorial% cat kkqueen.par

                mode gen(?, ^).
                gen(N, [N|Xs]) <-
                  N > 0 :
                  N1 is N-1,
                  gen(N1, Xs).
                gen(0, []).

                mode append(?, ?, ^).
                append([A|X], Y, [A|Z]) <-
                  append[X, Y, Z).
                append([], Y, Y).

                mode count(?, ?, ^).
                count([], M, M).
                count([X|Xs], M, Total) <-
                  M1 is M + 1 ,
                  count(Xs, M1, Total).

                tutorial% parlog
                Parallel Parlog V1.4 - 12 Jun 1990
                Copyright (C) 1990, Parlog Group, Imperial College

                | ?- compile(kkqueen).
                [loading compiler]
                Compiling file kkqueen.par
                gen / 2

                ** Syntax Error: append([A|X],Y,[A|Z])<- append <<here>>[X,Y,Z).
                append / 3
                count / 3
                File kkqueen partially compiled:
                One or more syntax errors in or before:
                append / 3
                These clauses missing from the object code!

                yes
                | ?- halt.

                ncalls/utime = 6579 / 2.4 = 2741.25 RPS
                tutorial%



            _7._4.  _D_e_a_d_l_o_c_k

            When the evaluation of  a  query  cannot  terminate  because
            there are calls suspended on input matching constraints, the
            system prints out all  the  suspended  calls  and  then  the


                                         6





                                                             User Manual

            message :

                [deadlock]


            Note: goals which were suspended before a previous deadlock,
            or  were  executing  before  an  interrupt was typed, may be
            displayed among the list  of  goals  suspended  during  this
            deadlock.


            _8.  _M_O_D_U_L_E_S

            Parallel Parlog supports a simple module system  to  control
            the name space of predicates. This is based on the notion of
            a _c_u_r_r_e_n_t _m_o_d_u_l_e, which is the place where a query currently
            looks    for    predicate    definitions.    The   predicate
            current_module/1 returns the name of the current module, and
            module/1  changes  it  [see  section  7.  in  the  Reference
            Manual].

            When predicates are loaded into the system, they are  placed
            in  the  current  module.  Thus  a command such as <- module
            exmpl. at the top of the source file will cause  the  predi-
            cates  in  the  object  file to be loaded into module exmpl.
            However, after the load  is  finished,  the  current  module
            becomes the module which was being used prior to the load.

            By default, predicates loaded into a module are  private  to
            that  module  and  can  only  be called by goals within that
            module. Predicates can be made visible to all other  modules
            by  the _p_u_b_l_i_c/_1 command, e.g.  public a/1, b/2, c/3., which
            means that it can be  invoked  from  any  module.  A  public
            predicate  is read-only in all modules other than the one in
            which it is defined, so the definition of a public predicate
            not  in  the current module cannot be replaced in subsequent
            loads by an alternative (private) one.

            Predicates can also be imported into modules without  making
            them  public  to  all  modules. This is a two stage process:
            firstly the predicates are made exportable in the module  in
            which  they are defined with _e_x_p_o_r_t/_1, and secondly they are
            imported with _i_m_p_o_r_t/_2, from the module in  which  they  are
            defined  into  the current module.  For example, suppose the
            current module is set  to  foo,  then  export([a/1,b/2,c/3])
            makes  predicates  a/1,  b/2  and c/3 all exportable. Now in
            module bar, the predicate b/2 can be imported from foo using
            import(foo,[b/2])..

            There are two predefined modules: _s_y_s_t_e_m and _u_s_e_r.  All Par-
            log  systems predicates, as defined in the reference manual,
            are defined in module _s_y_s_t_e_m and are made  public.  In  this
            way,  the  module  mechanism  is transparent to the user who
            does not wish to use it.  The query  evaluator  executes  by
            default  in  module  _u_s_e_r so that private predicates used by
            the system and compiler are invisible to the user.


                                         7





                                                             User Manual

            The binding of a call to  a  predicate  in  the  appropriate
            module  is  done at load time, thus incurring no overhead at
            run time. However, the binding for interpreted calls,  using
            call/1,  is  done  at run time in the context of the current
            module. Thus, the predicate must either be  in  the  current
            module  or  imported  into  it.  A  predicate within a given
            module can be called explicitly using the  _m_o_d_u_l_e#_g_o_a_l  syn-
            tax, e.g.


                | ?- system#assemble(file).



            _9.  _G_U_A_R_D _S_A_F_E_T_Y _C_O_N_S_I_D_E_R_A_T_I_O_N_S

            The usual guard safety restrictions apply, which  mean  that
            bindings of variables in a guard are not made visible to the
            body of the clause until the guard has committed.

            In addition, Parallel Prolog has a nonflat guard restriction
            which  means  that  only one clause can be tried once a con-
            junction of nonflat clauses has been encountered. A  nonflat
            clause  is one with a nonflat guard, which generally means a
            user-defined guard predicate or conjunction  of  predicates.
            System-defined flat predicates include all unification prim-
            itives (except ground/1 and \==/2), all  type  tests,  is/2,
            term  comparison and arithmetic comparison.  More details on
            flat and non-flat guards can be found in [Gregory 1987].

            The consequence of this nonflat guard  restriction  is  that
            the  programmer  should  ensure  that all clauses containing
            nonflat guards (except the last) should end with  a  sequen-
            tial  clause  separator ;.  This coding strategy will ensure
            that a candidate nonflat clause will not be tried in  paral-
            lel with other candidates.

            With this restriction, the if-then-else form of  deep  guard
            is  still  possible  (as  seen in examples 1 and 2), but the
            or-parallel search technique - two alternative  guards  exe-
            cuting in parallel - is not (example 3).


                (1) mode p1(?,^).
                   p1(X,S) <- try(X) : S=ok ;
                   p1(X,S) <- S=failed.

                (2) mode p2(?,?).
                   p2([A|B],Y) <- g1(A), g2(A) : b1(B,Y);
                   p2(X,[A|B]) <- g1(A), g2(A) : b2(B,X);
                   p2(X,Y)     <- b3(X,Y).

                (3) % this is not allowed:
                   mode p3(?,?,?,^).
                   p3(X,L,R,T) <- find(X,L,T1) : T=T1.
                   p3(X,L,R,T) <- find(X,R,T2) : T=T2.


                                         8





                                                             User Manual

            There are transformations that automatically convert general
            Parlog  into  the  restricted  form, and future releases may
            perform these during compilation.  At present, the  user  is
            responsible for any alterations to his code.






















































                                         9





                                                        Reference Manual

            _R_E_F_E_R_E_N_C_E _M_A_N_U_A_L


            _1.  _S_Y_N_T_A_X

            A Parlog program consists of a finite set of _g_u_a_r_d_e_d _c_l_a_u_s_e_s
            and _m_o_d_e _d_e_c_l_a_r_a_t_i_o_n_s.  A guarded clause has the form:
                    H <- G<1>, ..., G<m> : B<1>, ..., B<n>  (m,n >= 0)

            where _H is called the _c_l_a_u_s_e _h_e_a_d, _G<_1>, ...,  _G<_m>  is  its
            _g_u_a_r_d  and  _B<_1>,  ...,  _B<_n>  its  _b_o_d_y.  The : is a _c_o_m_m_i_t
            _o_p_e_r_a_t_o_r.  If the guard is empty (i.e.  _m = 0) then the com-
            mit operator can be omitted.

            The clause head _H and each of the _G<_1>, ..., _G<_m> and  _B<_1>,
            ..., _B<_n> are _g_o_a_l_s.  A goal has the form:
                    R(T<1>, ..., T<k>)      (k >= 0)

            where _R is the _r_e_l_a_t_i_o_n _n_a_m_e and _T<_1>,  ...,  _T<_k>  are  its
            _a_r_g_u_m_e_n_t  _t_e_r_m_s.   The  number of arguments, _k is called the
            goal's _a_r_i_t_y.  If the goal has no arguments (i.e.   _k  =  0)
            then  the brackets are omitted.  A _r_e_l_a_t_i_o_n or _p_r_o_c_e_d_u_r_e R/k
            comprises all clauses with the relation name _R and arity _k.

            A _m_o_d_e _d_e_c_l_a_r_a_t_i_o_n is associated with  a  Parlog  procedure.
            For a relation R/k this has the form:
                    mode R(m<1>, .., m<k>).

            where each _m<_i> is either ? or ^.  A ? denotes an _i_n_p_u_t mode
            and  a  ^  denotes  an _o_u_t_p_u_t mode. If a mode declaration is
            omitted for a relation _R then all of its argument terms  are
            assumed  to have an input mode.  A mode _m<_i> can be prefixed
            with argument names; these are comments of no semantic  sig-
            nificance.

            A _t_e_r_m can be a variable, constant  or  structured  term.  A
            _v_a_r_i_a_b_l_e  is denoted by an identifier beginning with a capi-
            tal letter or the underscore character _. Examples are X and
            Tree.   The underscore character may also be used on its own
            to denote a unique _a_n_o_n_y_m_o_u_s or _s_i_n_g_l_e_t_o_n variable.  A  _c_o_n_-
            _s_t_a_n_t  is either an integer or a name denoted by any charac-
            ter string, which must be enclosed in single quotes when  it
            can  be confused with other types of term; examples are jim,
            'Hello World' and $primitive.  A _s_t_r_u_c_t_u_r_e_d _t_e_r_m is  denoted
            by:
                    F(T<1>, ..., T<n>)      (n >= 1)

            where _F is the _f_u_n_c_t_o_r _n_a_m_e and  the  _a_r_g_u_m_e_n_t_s  _T<_1>,  ...,
            _T<_k>  are  terms.   An  example  of  a  structured  term  is
            point(X,Y,Z), whose functor name is point of arity  3,  with
            arguments  X,  Y and Z.  Infix notation may be used for cer-
            tain structured terms where the functor  is  defined  as  an
            operator; thus the term =(X,Y) can be written as X=Y.

            A special syntax is used for the  type  of  structured  term
            known  as  _l_i_s_t_s.   The notation [_H|_T] is used to denote the


                                         10





                                                        Reference Manual

            list with the head  _H  and  tail  _T.   A  nested  list  term
            [X|[Y|Z]]  may  be  abbreviated  as  [X,Y|Z] and if _Z is the
            empty list or _n_i_l term (denoted by constant  [])  then  this
            can be abbreviated to [X,Y].

            A Parlog program is invoked by executing a _q_u_e_r_y.   A  query
            is a conjunction of goals:
                    ?- Q<1>, ..., Q<n>      (n >= 1)

            Goals in a clause or query may be separated by the  _p_a_r_a_l_l_e_l
            _c_o_n_j_u_n_c_t_i_o_n  operator,  ,,  or  the  _s_e_q_u_e_n_t_i_a_l  _c_o_n_j_u_n_c_t_i_o_n
            operator,  &.  Similarly,  clauses  in  a  relation  may  be
            separated  by Parlog's _p_a_r_a_l_l_e_l and _s_e_q_u_e_n_t_i_a_l _c_l_a_u_s_e _s_e_a_r_c_h
            operators, denoted as . and ;  respectively.   In  addition,
            the last clause of a relation is always terminated by

            Programs may include comments, which are defined as any text
            following a % character up to the next newline character.



            _2.  _S_E_M_A_N_T_I_C_S

            Parlog differs from Prolog in  three  important  respects  :
            concurrent  evaluation,  don't-care non-determinism, and its
            (optional) use of mode declarations to specify communication
            constraints on shared variables.

            During the evaluation of a call r(t1',...,tk'), all  of  the
            clauses  for  the  predicate 'r' can be searched in parallel
            for a candidate clause. The clause :
                   r(t1, . . ., tk)  <-  < guard >  :  < body >

            is a candidate clause if the head r(t1,...,tk)  matches  the
            call  r(t1',...,  tk') and the guard succeeds.  It is a non-
            candidate if the match or the guard fails.  If  all  clauses
            are non-candidates the call fails, otherwise one of the can-
            didate clauses is selected and the call is  reduced  to  the
            substitution instance of the body of that clause.

            There is no backtracking on the choice of  candidate  clause
            since  we  _d_o_n'_t _c_a_r_e which candidate clause is selected. In
            practice, the  language  implementation  dictates  that  the
            first  one  (chronologically)  to  be  found is chosen.  The
            absence of backtracking in  Parlog  is  compensated  for  by
            guard  tests which can be used to guarantee that the correct
            clause is chosen. This idea has been more formally stated in
            Gregory's  _s_u_f_f_i_c_i_e_n_t _g_u_a_r_d_s _l_a_w [Gregory 1987], which iden-
            tifies the  situations  under  which  a  Parlog  computation
            returns  a  solution  to  a  query, if a solution exists. It
            states that Parlog predicates  should  be  written  so  that
            guards in each clause guarantee that if a clause is selected
            to reduce a goal then either a solution to the call  can  be
            computed  using  this  clause,  or  no solution can be found
            using any other clause.



                                         11





                                                        Reference Manual

            The search for a candidate clause can be controlled by using
            either  the  parallel  clause  search  operator  '.'  or the
            sequential clause search operator ';' between  clauses.  For
            instance, if a predicate is defined by the clauses :

                Clause1  .
                Clause2  ;
                Clause3.


            Then Clause3 will not be  tried  for  candidacy  until  both
            Clause1  and  Clause2  have  been  found to be non-candidate
            clauses.

            Non-variable terms that appear in input  argument  positions
            in the head of a clause can only be used for input matching.
            If an argument of the call is not sufficiently  instantiated
            for an input match to succeed, the attempt to use the clause
            suspends until some other process further  instantiates  the
            input  argument  of the call.  If all clauses for a call are
            suspended, the call suspends but a candidate clause  can  be
            selected even if there are other suspended clauses.

            Parlog utilises unification for output bindings which  means
            that  bindings  to output variables will be unified with any
            values in those argument positions in the goal.
































                                         12





                                                        Reference Manual

            _3.  _C_O_M_M_A_N_D _L_I_N_E _O_P_T_I_O_N_S



                 -n _x Specifies the number of processors to execute.
                      The default value is -n1.

                 -m _x Specifies the number of memory segments  (i.e.
                      64Kbyte  blocks)  to  allocate on startup. The
                      default value is 7 + 5 x _n,  where  _n  is  the
                      number of processors.


            On machines that allow shared memory to be  expanded  during
            execution  there should be no reason to use the -m option as
            the system can allocate extra  memory  if  needed  automati-
            cally.  Currently  the Alliant, Sequent Balance and Symmetry
            and the uniprocessor versions of  the  system  support  this
            memory expansion feature.



            _4.  _S_Y_S_T_E_M _O_P_E_R_A_T_O_R _D_E_C_L_A_R_A_T_I_O_N_S

            The following list specifies the operators  defined  in  the
            system operator set.


                op(system, 1400, xfy, ';')  &
                op(system, 1350, xfy, '..') &
                op(system, 1300, xfy, '\\') &
                op(system, 1200, xfx, (<-)) &
                op(system, 1200,  fx, (<-)) &
                op(system, 1150,  fx, [(mode),(public),(prolog)]) &
                op(system, 1150, xfx, :)    &
                op(system, 1100, xfy, &)    &
                op(system, 1050, xfy, and)  &
                op(system, 1000, xfy, ',')  &
                op(system,  700, xfx, [is,=,=..,\=,==,\==,<=,=@=,\=@=,@<,@>,
                                       @=<,@>=,=:=,=\=,<,>,=<,>=])   &
                op(system,  600, xf , [?,^])   &
                op(system,  500, yfx, [+,-,/\,\/,\]) &
                op(system,  500,  fx, [+,-,\])  &
                op(system,  400, yfx, [*,/,//,<<,>>]) &
                op(system,  300, xfx, [div,mod])      &
                op(system,  200, xfx, #).



            _5.  _S_Y_S_T_E_M _P_R_E_D_I_C_A_T_E_S


            _5._1.  _U_N_I_F_I_C_A_T_I_O_N _R_E_L_A_T_E_D

            Term1 = Term2



                                         13





                                                        Reference Manual

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: No suspension.

                 _b_e_h_a_v_i_o_u_r: Output unification.  Attempts to unify Term1
                 with  Term2.  Succeeds  if  Term1 and Term2 unify; else
                 fails.


            Term1 == Term2

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends if Term1  and  Term2  can  be
                 unified only by binding variables in both of them.

                 _b_e_h_a_v_i_o_u_r: Test unification. It unifies Term1 and Term2
                 without  binding  variables in either term. Succeeds if
                 Term1 and Term2 are identical terms; fails as  soon  as
                 Term1 and Term2 fail to match.


            Term1 \== Term2

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: As for ==/2 above.

                 _b_e_h_a_v_i_o_u_r: Tests Term1 and Term2 without binding  vari-
                 ables  in either.  Fails if Term1 and Term2 are identi-
                 cal terms; succeeds as soon as Term1 and Term2 fail  to
                 match.


            Term1 <= Term2

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends if Term1 and Term2 could only
                 be unified by binding variables in Term2

                 _b_e_h_a_v_i_o_u_r: Input matching.   Unifies  Term1  and  Term2
                 without  binding variables in Term2.  Succeeds if Term2
                 is a substitution instance of Term1.  Fails as soon  as
                 Term1 and Term2 fail to match.


            var(X)

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: No suspension.

                 _b_e_h_a_v_i_o_u_r: Succeeds if X is an unbound variable.  Fails
                 if it is instantiated.


            nonvar(X)

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: No suspension.

                 _b_e_h_a_v_i_o_u_r: Fails if X is an unbound variable.  Succeeds
                 if it is instantiated.





                                         14





                                                        Reference Manual

            ground(X)

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until X is ground.

                 _b_e_h_a_v_i_o_u_r: Succeeds when X is ground.


            data(X)

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until X is instantiated.

                 _b_e_h_a_v_i_o_u_r: Succeeds when X is instantiated.


            _5._2.  _T_Y_P_E _T_E_S_T_S


            atom(X)

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until X is instantiated.

                 _b_e_h_a_v_i_o_u_r: Succeeds if X is an atom; otherwise fails.


            atomic(X)

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until X is instantiated.

                 _b_e_h_a_v_i_o_u_r: Succeeds if X is an atom or a number; other-
                 wise fails.


            integer(X)

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until X is instantiated.

                 _b_e_h_a_v_i_o_u_r: Succeeds  if  X  is  an  integer;  otherwise
                 fails.


            float(X)

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until X is instantiated.

                 _b_e_h_a_v_i_o_u_r: Succeeds if X is a  floating  point  number;
                 otherwise fails.


            number(X)

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until X is instantiated.

                 _b_e_h_a_v_i_o_u_r: Succeeds if X is an integer  or  a  floating
                 point number; otherwise fails.




                                         15





                                                        Reference Manual

            _5._3.  _A_R_I_T_H_M_E_T_I_C _E_X_P_R_E_S_S_I_O_N_S


            Value is Expression

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until Expression is ground.

                 _b_e_h_a_v_i_o_u_r: Expression is  evaluated  as  an  arithmetic
                 expression,  and  the  resulting number is unified with
                 Value. If any of the variables are bound to non-numeric
                 values,  then the goal fails.  An arithmetic expression
                 is a term built from numbers, variables,  and  functors
                 that   represent  arithmetic  functions.  The  functors
                 available in Parlog are given below.  In the following,
                 X and Y are considered to be arithmetic expressions.



                 +X                  Results in the  positive  value
                                     of X. The type of the result is
                                     the same as  the  type  of  the
                                     operand.


                 -X                  Results in the  negative  value
                                     of X. The type of the result is
                                     the same as  the  type  of  the
                                     operand.


                 \X                  Results in the  complements  of
                                     the bits in X.


                 integer(X)          Results in X if it  is  an  in-
                                     teger.  Otherwise,  if  it is a
                                     float,  the   result   is   the
                                     nearest integer that is between
                                     it and 0.


                 float(X)            Results in X if it is a  float.
                                     Otherwise, if it is an integer,
                                     the  result  is  the   floating
                                     point equivalent.


                 X+Y                 Results in the sum of X and  Y.
                                     If  both operands are integers,
                                     the result is an integer;  oth-
                                     erwise the result is a float.


                 X-Y                 Results in the difference of  X
                                     and Y. If both operands are in-
                                     tegers, the result  is  an  in-


                                         16





                                                        Reference Manual

                                     teger;  otherwise the result is
                                     a float.


                 X*Y                 Results in the product of X and
                                     Y.  If  both  operands  are in-
                                     tegers, the result  is  an  in-
                                     teger;  otherwise the result is
                                     a float.


                 X/Y                 Results in the  quotient  of  X
                                     and  Y.  The resultant value is
                                     always a float,  regardless  of
                                     the types of the operands.


                 X//Y                Results in the integer quotient
                                     of X and Y. The resultant value
                                     is  always  a  (truncated)  in-
                                     teger.


                 X mod Y             Results in the remainder  after
                                     the integer division of X by Y.
                                     The result always has the  same
                                     sign as X.


                 X/\Y                Results in the bitwise conjunc-
                                     tion of X and Y.


                 X\/Y                Results in the bitwise disjunc-
                                     tion of X and Y.


                 X<<Y                X is left-shifted Y places.


                 X>>Y                X  is  right-shifted  Y  places
                                     with sign extension.




            _6.  _T_E_R_M _C_O_M_P_A_R_I_S_O_N

            X=@=Y

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until X  and  Y  are  instan-
                 tiated.

                 _b_e_h_a_v_i_o_u_r: Succeeds if X is lexically equal to Y;  else
                 fails.



                                         17





                                                        Reference Manual

            X\=@=Y

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until X  and  Y  are  instan-
                 tiated.

                 _b_e_h_a_v_i_o_u_r: Succeeds if X is lexically not equal  to  Y;
                 else fails.


            X@<Y

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until X  and  Y  are  instan-
                 tiated.

                 _b_e_h_a_v_i_o_u_r: Succeeds if X is lexically less than Y; else
                 fails.


            X@>Y

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until X  and  Y  are  instan-
                 tiated.

                 _b_e_h_a_v_i_o_u_r: Succeeds if X is lexically more than Y; else
                 fails.


            X@=<Y

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until X  and  Y  are  instan-
                 tiated.

                 _b_e_h_a_v_i_o_u_r: Succeeds if X  is  lexically  less  than  or
                 equal to Y; else fails.


            X@>=Y

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until X  and  Y  are  instan-
                 tiated.

                 _b_e_h_a_v_i_o_u_r: Succeeds if X  is  lexically  more  than  or
                 equal to Y; else fails.


            X=:=Y

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until X  and  Y  are  instan-
                 tiated.

                 _b_e_h_a_v_i_o_u_r: X and  Y  must  be  numbers,  and  the  goal
                 succeeds if they are equal.


            X=\=Y



                                         18





                                                        Reference Manual

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until X  and  Y  are  instan-
                 tiated.

                 _b_e_h_a_v_i_o_u_r: X and  Y  must  be  numbers,  and  the  goal
                 succeeds if they are not equal.


            X<Y

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until X  and  Y  are  instan-
                 tiated.

                 _b_e_h_a_v_i_o_u_r: X and  Y  must  be  numbers,  and  the  goal
                 succeeds if X is strictly less than Y.


            X>Y

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until X  and  Y  are  instan-
                 tiated.

                 _b_e_h_a_v_i_o_u_r: X and  Y  must  be  numbers,  and  the  goal
                 succeeds if X is strictly greater than Y.


            X=<Y

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until X  and  Y  are  instan-
                 tiated.

                 _b_e_h_a_v_i_o_u_r: X and  Y  must  be  numbers,  and  the  goal
                 succeeds if X is less than or equal to Y.


            X>=Y

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until X  and  Y  are  instan-
                 tiated.

                 _b_e_h_a_v_i_o_u_r: X and  Y  must  be  numbers,  and  the  goal
                 succeeds if X is greater than or equal to Y.


            _6._1.  _T_E_R_M _M_A_N_I_P_U_L_A_T_I_O_N


            name(Atomic,String)

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until either Atomic or String
                 is instantiated.

                 _b_e_h_a_v_i_o_u_r: If Atomic is instantiated  (it  must  be  an
                 atom or a number), then string is unified with the list
                 of character codes in its name.  If  String  is  ground
                 (it  must be a list of character codes), Atomic is uni-
                 fied with the number if possible,  otherwise  the  atom


                                         19





                                                        Reference Manual

                 containing  those  characters.   Note  that in Parallel
                 Parlog   "add",   for   example,   is   shorthand   for
                 [97,100,100].


            Term =.. List

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until either Term or List  is
                 instantiated.

                 _b_e_h_a_v_i_o_u_r: List is  a  list  whose  head  is  the  atom
                 corresponding  to  the  principal  functor  of Term and
                 whose tail is a list of the arguments of Term. If  Term
                 is  uninstantiated,  then  List  must  be  instantiated
                 either to a list of determinate length whose head is an
                 atom, or to a list of length 1 whose head is a number.


            functor(Term,Functor,Arity)

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until Term  is  instantiated,
                 or Functor and Arity are instantiated.

                 _b_e_h_a_v_i_o_u_r: If Term is instantiated, Functor  and  Arity
                 will  be  bound  to  the  functor and arity of Term. If
                 Functor and Arity are instantiated, Term will be  bound
                 to the most general Term having this name and arity.


            arg(N,Term,Arg)

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until N and Term are  instan-
                 tiated.

                 _b_e_h_a_v_i_o_u_r: Initially, N must be instantiated to a posi-
                 tive integer and Term to a compound term. The result of
                 the call is to unify Arg with the Nth argument of Term.
                 (The  arguments  are  numbered from 1 upwards).  If the
                 initial conditions are not satisfied or  N  is  out  of
                 range, the call fails.


            copy_term(Term1,Term2)

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: No suspension.

                 _b_e_h_a_v_i_o_u_r: A copy of Term1 with new variables  is  uni-
                 fied with Term2.


            _6._2.  _M_E_T_A_L_E_V_E_L


            call(Call)




                                         20





                                                        Reference Manual

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until Call is instantiated.

                 _b_e_h_a_v_i_o_u_r: If Call is instantiated to an atom  or  com-
                 pound  term,  then  the  goal  call(Call)  is  executed
                 exactly as if  that  term  appeared  textually  in  its
                 place.  If Call fails, then call(Call) fails. call/3 is
                 also available but contains a fault [see section 11. of
                 the Reference Manual].


            Module#Call

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until  Module  and  Call  are
                 bound.

                 _b_e_h_a_v_i_o_u_r: Evaluates Call as it is defined  in  Module.
                 Succeeds if Call succeeds.  Fails if Call fails.


            fail

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: No suspension.

                 _b_e_h_a_v_i_o_u_r: Fails.


            not(Call)

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until Call is bound.

                 _b_e_h_a_v_i_o_u_r: This fails if the goal Call has a  solution,
                 and  succeeds  otherwise.  This  is  not real negation,
                 which is  not  possible  in  Parlog,  but  negation-by-
                 failure meaning that P is not provable.


            halt

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: No suspension.

                 _b_e_h_a_v_i_o_u_r: Terminates the Parallel Parlog session.


            true

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: No suspension

                 _b_e_h_a_v_i_o_u_r: Always succeeds.


            _6._3.  _I_N_P_U_T _A_N_D _O_U_T_P_U_T


            Input and output is dealt  with  by  utilising  streams.   A
            stream  can  refer  to  a file or to a terminal, and must be
            either an input or an output stream.  At any time, there  is


                                         21





                                                        Reference Manual

            one  current  input  stream  and  one current output stream.
            Input and output predicates fall into two categories:

            1) Those that use the current input and output stream.

            2) Those which take an explicit stream argument.

            The  standard  streams   are   identified   by   user_input,
            user_output,  or user_error. Other streams are identified by
            the term returned by open/3  in  its  _S_t_r_e_a_m  argument  (see
            below).

            The current input and output streams are set  to  user_input
            and user_output upon entry to the Parallel Parlog system.


            _6._3._1.  _S_T_R_E_A_M_S

            open(File,Mode,Stream)

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n:  Suspends  until  File  and  Mode  are
                 instantiated.

                 _b_e_h_a_v_i_o_u_r: If Mode is the atom read,  and  File  is  an
                 existing  file  for  which the user has read permission
                 then  it  succeeds,  unifying  Stream   with   a   term
                 representing  an input stream for File.  If mode is the
                 atom write and the user has permission to write to  the
                 file  then  it  succeeds,  unifying  Stream with a term
                 representing an output stream for File.  If mode is the
                 atom  append and File is an existing file for which the
                 user has write permission then  it  succeeds,  unifying
                 Stream  with  a  term representing an output stream for
                 appending to File. Otherwise the predicate fails.


            close(Stream)

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until Stream is instantiated.

                 _b_e_h_a_v_i_o_u_r: If Stream is an open stream then it succeeds
                 and closes the stream; otherwise it fails. Failure will
                 also occur if Stream is the stream for  standard  input
                 or output.


            set_input(Stream)

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until Stream is instantiated.

                 _b_e_h_a_v_i_o_u_r:  If  Stream  is  an  open  stream  then   it
                 succeeds,  setting  the  current  input  to the stream.
                 Otherwise it fails.





                                         22





                                                        Reference Manual

            set_output(Stream)

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until Stream is instantiated.

                 _b_e_h_a_v_i_o_u_r:  If  Stream  is  an  open  stream  then   it
                 succeeds,  setting  the  current  output to the stream.
                 Otherwise it fails.


            current_input(Stream)

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: No suspension.

                 _b_e_h_a_v_i_o_u_r: This causes Stream to be  unified  with  the
                 current input stream.


            current_output(Stream)

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: No suspension.

                 _b_e_h_a_v_i_o_u_r: This causes Stream to be  unified  with  the
                 current output stream.


            clear_input(Stream)

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until Stream is instantiated.

                 _b_e_h_a_v_i_o_u_r: Flushes the input buffer associated with the
                 given  stream.   For terminal input this means throwing
                 away the rest of the current line.   The  current  line
                 being the sequence of characters input but not yet read
                 off the stream.


            flush_output(Stream)

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until Stream is instantiated.

                 _b_e_h_a_v_i_o_u_r: Flushes the output  buffer  associated  with
                 the given stream.


            _6._3._2.  _C_H_A_R_A_C_T_E_R _I/_O


            get0(Stream,N)

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until Stream is instantiated.

                 _b_e_h_a_v_i_o_u_r: Unifies N with the ASCII code  of  the  next
                 character from the input stream Stream.  If end of file
                 is encountered, N is unified with the atom end_of_file.
                 If  the  end  of stream was reached on a previous input
                 command, then this call will give an error message  and


                                         23





                                                        Reference Manual

                 abort the computation.



            get(Stream,N)

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until Stream is instantiated.

                 _b_e_h_a_v_i_o_u_r: Unifies N with the ASCII code  of  the  next
                 non-space character from the input stream Stream. Space
                 characters are all those with ASCII codes less than  or
                 equal to 32; this includes space, tab, linefeed and all
                 control characters.  If end of file is  encountered,  N
                 is  unified  with  the  atom end_of_file. If the end of
                 stream was reached on a previous  input  command,  then
                 this call will give an error message and abort the com-
                 putation. get/2 should not be used with user_input.


            skip(Stream,N)

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n:  Suspends  until  Stream  and  N   are
                 instantiated.

                 _b_e_h_a_v_i_o_u_r: Advances the input stream Stream to  immedi-
                 ately  past the character represented by the ASCII code
                 N (N must be an integer). If end of file is encountered
                 N is unified with the atom end_of_file.  If N is not an
                 integer, or is an integer  outside  the  range  0..127,
                 then the call fails after issuing an error.


            put(Stream,N)

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n:  Suspends  until  Stream  and  N   are
                 instantiated.

                 _b_e_h_a_v_i_o_u_r: Writes  the  character  represented  by  the
                 ASCII  code N to the stream represented by Stream. If N
                 is not an integer, or is an integer outside  the  range
                 0..127, then the call fails after reporting an error.



            nl(Stream)

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until Stream is instantiated.

                 _b_e_h_a_v_i_o_u_r: Starts a  new  line  on  the  output  stream
                 Stream.  It is equivalent to put(Stream,10).


            tab(Stream,N)

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n:  Suspends  until  Stream  and  N   are
                 instantiated.


                                         24





                                                        Reference Manual

                 _b_e_h_a_v_i_o_u_r: Writes N spaces to the output stream Stream.
                 N  must be an integer; otherwise an error is issued and
                 the call fails.


            The following predicates are equivalent  to  their  counter-
            parts  above,  except  that  they act upon the current input
            stream :

                    get0(N)      get(N)       skip(N)

            In an analogous manner, the predicates below  act  upon  the
            current output stream :

                    put(N)       nl               tab(N)



            _6._3._3.  _T_E_R_M _I/_O

            read(Stream,Term)

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until Stream is instantiated.

                 _b_e_h_a_v_i_o_u_r: Reads the next Parlog term  from  the  input
                 stream  Stream and unifies it with Term.  The term must
                 be terminated by a full stop followed by a space  char-
                 acter or a newline.  These will be consumed by the call
                 but not returned  in  Term.  When  a  syntax  error  is
                 encountered,  an  error  message is printed which indi-
                 cates where the error occurs in the input, and the call
                 then fails.  If the end of the file is encountered then
                 the atom end_of_file is unified with Term. If  the  end
                 of stream was reached on a previous input command, then
                 this call will produce an error message and  abort  the
                 computation.


            read(Stream,OpSet,Term,Variables)

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until Stream  and  Opset  are
                 bound.

                 _b_e_h_a_v_i_o_u_r: As for read/2 except that the  operator  set
                 given by OpSet is used to parse the term, and Variables
                 is unified with a list of (Atom,Variable) pairs  giving
                 the atom representation of each variable in the term.


            display(Stream,Term)

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until  Stream  and  Term  are
                 instantiated.

                 _b_e_h_a_v_i_o_u_r: Writes the term Term to  the  output  stream
                 Stream  in  prefix  notation,  with no quotes for atoms


                                         25





                                                        Reference Manual

                 that need quoting in order to be read back in.


            write(Stream,Term)

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until  Stream  and  Term  are
                 instantiated.

                 _b_e_h_a_v_i_o_u_r: Writes the term Term to  the  output  stream
                 Stream  according  to  the  operator precedences of the
                 system operator set, with no quotes for atoms that need
                 quoting  in order to be read back in [see section 4. of
                 the Reference Manual].


            writeq(Stream,Term)

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until  Stream  and  Term  are
                 instantiated.

                 _b_e_h_a_v_i_o_u_r: Writes in the same way as write/2, but  with
                 quotes  around  atoms  that need quoting in order to be
                 read back in.


            write_canonical(Stream,Term)

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until  Stream  and  Term  are
                 instantiated.

                 _b_e_h_a_v_i_o_u_r: Writes the term Term to  the  output  stream
                 Stream,  with  quotes around atoms that need quoting in
                 order to be read back in.


            The predicates below are equivalent  to  their  counterparts
            above, except that they act upon the current output stream :

                  display(Term)           write(Term)
                  writeq(Term)            write_canonical(Term)

            As expected, read/2 has a short form for  reading  from  the
            current input stream :

                  read(Term)



            _7.  _C_O_M_P_I_L_A_T_I_O_N _A_N_D _L_O_A_D_I_N_G

            compile(File)

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until File is instantiated.

                 _b_e_h_a_v_i_o_u_r: Compiles a Parlog source  code  file.   Ini-
                 tially,  the  name File is sought as the input file; if


                                         26





                                                        Reference Manual

                 that does not exist then  File  is  tried  with  '.par'
                 appended to it. If still no match is found, an error is
                 issued and the call succeeds. If the  compiler  is  not
                 already loaded, then a call to compile/1 will automati-
                 cally load it.


            load(File)

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until File is instantiated.

                 _b_e_h_a_v_i_o_u_r: Loads a Parlog object code file.  Initially,
                 the  name  File  is sought; if that does not exist then
                 File with '.o' appended is tried.  If still no match is
                 found, an error is issued and the call fails.


            public Preds

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until Preds is ground.

                 _b_e_h_a_v_i_o_u_r: Preds  is  expected  to  be  a  sequence  of
                 Name/Arity pairs that represent predicate names, other-
                 wise the call fails.  If a call to  public/1  succeeds,
                 these predicates become visible to all other modules.


            export(Predicates)

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until Predicates is ground.

                 _b_e_h_a_v_i_o_u_r: The predicates list is expected  to  consist
                 of  Name/Arity  pairs  that  represent predicate names,
                 otherwise the call fails. This enables  the  predicates
                 listed  (which  should be private to this module) to be
                 imported into other modules with import/2.


            import(Module,Predicates)

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until Module  and  Predicates
                 are ground.

                 _b_e_h_a_v_i_o_u_r: The Predicates list is expected  to  consist
                 of  Name/Arity  pairs  that  represent predicate names,
                 otherwise the call fails. This imports the  definitions
                 of  Predicates  from Module into the current module and
                 can be  used  by  code  subsequently  loaded  into  the
                 current module.


            module(Module)

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until Module is instantiated.




                                         27





                                                        Reference Manual

                 _b_e_h_a_v_i_o_u_r: Makes Module the current module.


            current_module(Module)

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: No suspension.

                 _b_e_h_a_v_i_o_u_r: Unifies Module with the current module.


            _7._1.  _M_I_S_C_E_L_L_A_N_E_O_U_S


            op(OpSet,Precedence,Type,Op)

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until all four arguments  are
                 instantiated.

                 _b_e_h_a_v_i_o_u_r: Inserts atoms into the  operator  set  OpSet
                 with  the  specified  precedence  and type.  Precedence
                 should be an integer between 1 and 1200, Type should be
                 one of fx, fy, yf, xfx, xfy or yfx, and Op should be an
                 atom or a list of atoms.


            current_op(OpSet,Precedence,Type,Op)

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until OpSet,Type and  Op  are
                 instantiated.

                 _b_e_h_a_v_i_o_u_r: Returns the precedence of  the  Op  operator
                 declared in the OpSet operator set.  Type should be one
                 of fx, fy, yf, xfx, xfy or yfx, Op should be  an  atom,
                 and  OpSet  should  be an operator set.  If no match is
                 found in OpSet, but an operator is found in the  _s_y_s_t_e_m
                 operator  set, then the precedence of the system opera-
                 tor is returned.


            The following two system predicates are equivalent to  their
            counterparts  above,  except that they act upon the operator
            set _s_y_s_t_e_m:

                      op(Prec,Type,Op)          current_op(Prec,Type,Op)


            util(Package)

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until Package is bound.

                 _b_e_h_a_v_i_o_u_r: Loads predicates from the specified  package
                 in  the utilities directory; an example is the SPM com-
                 patibility package [see section  9.  of  the  Reference
                 Manual].




                                         28





                                                        Reference Manual

            statistics(Key,Val)

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until Key is bound.

                 _b_e_h_a_v_i_o_u_r: When Key is one of  the  atoms  suspensions,
                 gcs,  heap, stack, process, program, memory, runtime or
                 calls the appropriate values will be unified  with  Val
                 and the predicate will succeed; otherwise it will fail.
                 For memory values (when Key has the value heap,  stack,
                 process,  program or memory), Val is bound to a term of
                 the form [_m_e_m_o_r_y__u_s_e_d, _m_e_m_o_r_y__f_r_e_e]. These  values  are
                 given  in word (4 byte) units except for process, which
                 is given in process (32 byte) units, and  memory  which
                 returns the total size of the allocated and free memory
                 segments in bytes.  When Key is runtime, Val  is  bound
                 to a list of the form [_t_o_t_a_l, _l_a_s_t], where _t_o_t_a_l is the
                 user cpu time since  the  Parallel  Parlog  system  was
                 invoked,  and  _l_a_s_t  is the time since the last call to
                 statistics/2 or statistics/0.


            statistics

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: No suspension.

                 _b_e_h_a_v_i_o_u_r: Prints  out  all  the  values  generated  by
                 statistics/2 onto the current output stream.


            unix(Command)

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n:  Suspends  until  Command  is  instan-
                 tiated.

                 _b_e_h_a_v_i_o_u_r: Can be used in the following ways:


                      unix(cd)            % change working directory to home directory
                      unix(cd(Path))      % change working directory to Path
                      unix(shell)         % invoke an interactive shell
                      unix(system(Cmd))   % pass Cmd to sh(1)
                      unix(access(File))  % test whether File is accessible (readable)



            load_foreign(Predicates,Obj,Libraries)

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until all three arguments are
                 instantiated.

                 _b_e_h_a_v_i_o_u_r: Loads C prediates into the system.  See sec-
                 tion 8. of the Reference Manual.


            load_foreign(Predicates,Obj)



                                         29





                                                        Reference Manual

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n:  Suspends  until  both  arguments  are
                 instantiated.

                 _b_e_h_a_v_i_o_u_r: As for load_foreign/3 but with no  libraries
                 specified.


            load_foreign_io(Predicates,Obj,Libraries)

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until all three arguments are
                 instantiated.

                 _b_e_h_a_v_i_o_u_r: Loads C prediates into the system  that  can
                 only  be executed by the master processor.  See section
                 8. of the Reference Manual.


            load_foreign_io(Predicates,Obj)

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n:  Suspends  until  both  arguments  are
                 instantiated.

                 _b_e_h_a_v_i_o_u_r:  As  for  load_foreign_io/3  but   with   no
                 libraries specified.


            spy(Pred)

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until Pred is instantiated.

                 _b_e_h_a_v_i_o_u_r: Pred must be a Name/Arity pair  representing
                 a  predicate  that  has already been loaded. If this is
                 the case, spy/1  succeeds,  setting  spypoints  on  the
                 named predicate; otherwise it fails.


            nospy(Pred)

                 _s_y_n_c_h_r_o_n_i_s_a_t_i_o_n: Suspends until Pred is instantiated.

                 _b_e_h_a_v_i_o_u_r: Pred must be a Name/Arity pair  representing
                 a  predicate  that has already been loaded.  If this is
                 the case, nospy/1 succeeds, removing spypoints from the
                 named predicate; otherwise it fails.














                                         30





                                                        Reference Manual

            _8.  _F_O_R_E_I_G_N _R_O_U_T_I_N_E_S

            The Parallel Parlog system allows C predicates to be  loaded
            dynamically  into the system either as predicates to be exe-
            cuted on any processor (using load_foreign/3), or predicates
            only    executable    by   the   master   processor   (using
            load_foreign_io/3).

            To aid integration of C routines into  the  Parlog  environ-
            ment,  a  _f_o_r_e_i_g_n  package  is  provided, for generating the
            _i_n_t_e_r_f_a_c_e routines that convert Parlog  data  types  into  C
            data  types  and invokes the C routines.  The interface rou-
            tines are generated from a file of  foreign/2  declarations,
            which have a similar format to those used by Quintus Prolog.


            _8._1.  _F_o_r_e_i_g_n _d_e_c_l_a_r_a_t_i_o_n_s

            The syntax of the foreign declarations is as follows :


                foreign( Function, PredicateSpecification ).

                PredicateSpecification = PredicateName(ArgSpec, ArgSpec,...)

                ArgSpec =  Arg?          - _i_n_p_u_t _a_r_g_u_m_e_n_t
                        |  Arg^          - _o_u_t_p_u_t _a_r_g_u_m_e_n_t
                        |  [Arg^]        - _a_r_g_u_m_e_n_t _f_o_r _t_h_e _f_u_n_c_t_i_o_n _r_e_t_u_r_n _v_a_l_u_e

                Arg = short | integer | float | string | atom


            In this context, _s_t_r_i_n_g refers to a  Parlog  atom  which  is
            converted to a C string; whereas _a_t_o_m refers to the internal
            representation of a Parlog atom (a  tagged  Word)  which  is
            passed directly to the C routine as a long unsigned integer.

            The following conversions are carried out according  to  the
            ArgSpec type :

                   Parlog: short? -->  _C: _i_n_t_e_g_e_r
                   Parlog: integer?    -->_C: _i_n_t_e_g_e_r
                   Parlog: float? -->  _C: _d_o_u_b_l_e
                   Parlog: string?     -->_C: _c_h_a_r *
                   Parlog: atom?  -->  _C: _W_o_r_d

                   Parlog: short^ <--  _C: _i_n_t_e_g_e_r *
                   Parlog: integer^    <--_C: _i_n_t_e_g_e_r *
                   Parlog: float^ <--  _C: _d_o_u_b_l_e *
                   Parlog: string^     <--_C: _c_h_a_r **
                   Parlog: atom^  <--  _C: _W_o_r_d *

                   Parlog: [short^]    <--_C: _r_e_t_u_r_n (_i_n_t_e_g_e_r)
                   Parlog: [integer^]  <--_C: _r_e_t_u_r_n (_i_n_t_e_g_e_r)
                   Parlog: [float^]    <--_C: _r_e_t_u_r_n (_d_o_u_b_l_e)
                   Parlog: [string^]   <--_C: _r_e_t_u_r_n (_c_h_a_r *)


                                         31





                                                        Reference Manual

                   Parlog: [atom^]     <--_C: _r_e_t_u_r_n (_W_o_r_d)

            Some examples of foreign declaration are :


                    foreign( sin, sin(float?, [float^]) ).
                    foreign( rename, rename(string?, string?) ).
                    foreign( test, tester(integer?, [integer^], atom?, atom^) ).



            _8._2.  _A_d_d_i_n_g _f_o_r_e_i_g_n _r_o_u_t_i_n_e_s

            The procedure for intergrating a C routine into the Parallel
            Parlog environment is as follows:


            1.   Consider a C routine strcat() which takes  two  strings
                 as  its  arguments and returns the concatenated string.
                 It is defined in _s_t_r_c_a_t._c, and is compiled to an object
                 file in the usual way :

                     cc -O -c strcat.c



            2.   A foreign declaration for this C routine is then placed
                 in a Parlog file, called _i_f_a_c_e._p_a_r:

                     foreign(strcat, strcat(string?, string?, [string^])).

                 This states that the  Parlog  predicate  strcat/3  will
                 call  the C routine strcat() and return its result as a
                 Parlog atom in its 3rd argument.


            3.   Now the interface file for this declaration can be gen-
                 erated  by  loading  the  foreign  package  and calling
                 make_interface/1 in the following way :


                     | ?- util(foreign).
                     [loading foreign]

                     yes
                     | ?- make_interface(iface).

                     yes


                 This produces a C file called  _i_f_a_c_e._c  which  must  be
                 then be compiled to an object file :

                     cc -O -c iface.c




                                         32





                                                        Reference Manual

            4.   The interface and C routine object  files  can  now  be
                 loaded  in to the Parlog system with the load_foreign/3
                 command :

                     | ?- load_foreign([strcat/3], 'iface.o', 'strcat.o').


                 strcat/3 is the name of the Parlog interface predicate,
                 _i_f_a_c_e._o  is  the  object  file  for the C interface and
                 _s_t_r_c_a_t._o is the object file for the original C routine.
                 Now the strcat/3 predicate can be invoked :


                     | ?- strcat(foo, bar, X).
                     X = foobar

                     yes



            In practise, an interface file can specify the interfaces to
            C  routines  in  several  files.  In that situation, the 3rd
            argument of load_foreign/3 or load_foreign_io/3 will contain
            several files and/or libraries, e.g.


                | ?- load_foreign_io([a/1, b/1, ..], 'iface.o', 'win1.o win2.o -lXlib').































                                         33





                                                        Reference Manual

            _9.  _A_N _A_L_T_E_R_N_A_T_I_V_E _T_R_A_C_E_R

            The _t_r_a_c_e utility  provides  a  more  comprehensive  tracing
            facility  which  allows the user to execute a Parlog program
            with set break points and trace points.  At  a  trace  point
            the  user is informed of some action which took place during
            execution. At a break point execution is halted and the user
            is able to investigate the current state of the system.

            The basis behind this tracer is that each clause in a Parlog
            program  may  be  considered as a rewrite rule. Any point in
            the execution of a query by the program may  be  represented
            by  a  list of goals. This list starts as the initial query,
            and the rewrite rules are continually applied  to  it  until
            either  it is empty, in which case the query succeeds, or no
            rewrite rule may be applied, in which case the query  fails.
            The  tracer  also  halts at deadlock, when no goal is suffi-
            ciently instantiated to allow a commitment to a  rewrite  to
            take place.


            _9._1.  _L_o_a_d_i_n_g _a_n_d _u_s_i_n_g _t_h_e _t_r_a_c_e_r

            The tracer is loaded with  the  command:  util(trace).   The
            program  to  be  traced should be in one or more files named
            <name>.par.  To enter the tracer type :

                partrace([<name >,<name >, ... , <name >]).
                               1       2              n
            where [<name >,<name >, ... , <name >]  is  a  list  of  the
            filenames  w1hich  co2ntain  the prognram to be traced (without
            the .par suffix).  The brackets may be omitted if  there  is
            only  one  file.   The  program  will  then be parsed by the
            tracer after which the tracer will query the  user  for  the
            sort of tracing required.

            The system will first prompt with:

                 Full trace?


            The user should reply y for yes or n for no.  In full  trace
            mode  every  time  a  goal commits to a clause the reduction
            made is printed out, a break is made in computation, and the
            user is prompted for a trace command.

            If the user chooses not to use full trace  mode  the  system
            will  first  ask  for  a  list of predicates to be traced on
            reduction. These should be entered one to a  line  and  fol-
            lowed by an empty line. If there is any ambiguity over arity
            a predicate name may be followed by a slash and  its  arity.
            For example :

                pred1
                pred2/2
                pred2/3


                                         34





                                                        Reference Manual

                pred3


            If the user just types  <return>  following  the  prompt  no
            predicate  will  be traced.  At any point in the computation
            when a goal for one of the  predicates  listed  for  tracing
            commits  to  a  clause  the reduction will be printed in the
            form:

                <_g_o_a_l> => <_b_o_d_y _o_f _n_e_w _c_l_a_u_s_e _w_i_t_h _v_a_r_i_a_b_l_e _b_i_n_d_i_n_g_s _p_a_s_s_e_d _t_h_r_o_u_g_h>

            If output modes are used, any unifications giving output are
            also printed in the form:

                <_v_a_r_i_a_b_l_e> <= <_t_e_r_m>


            Following the prompt for tracing, the user is prompted for a
            list  of  predicates  to  break  on  reduction.  The list is
            entered in the same way as above. When a goal for  a  predi-
            cate  in  this  second  list  commits, the reduction will be
            printed as before, but execution will  also  halt,  and  the
            user will be prompted for a trace command.

            Whether in full trace mode or not, the  user  will  also  be
            asked  for  a list of predicates to be traced on completion.
            This is a form of tracing based on the  procedural  view  of
            Parlog.  It  prints out the final form of a goal when it has
            completed execution. A goal has completed  execution  either
            if  it  reduces  to the empty list or if it has reduced to a
            list of subgoals all of which have  completed  execution.  A
            completion is indicated by the trace:

                * Completed * <goal>



            _9._2.  _T_r_a_c_e _C_o_m_m_a_n_d_s

            At a break point, the user is asked for a command  with  the
            prompt:

                Trace command :


            A <return> typed at this point will  display  the  state  of
            computation (see below), otherwise one of the following com-
            mands are can be typed:

                c - continue execution until next trace point

                f - give full display, including all goals following a sequential "&"
                g - give standard display and allow user to investigate goals

                h - give list of available commands
                q - quit execution


                                         35





                                                        Reference Manual

                t - reset trace information

                u - undo trace points and continue execution until completion



            _9._3.  _D_i_s_p_l_a_y_i_n_g _s_t_a_t_e _o_f _c_o_m_p_u_t_a_t_i_o_n

            At any point in the computation goals in the list of current
            goals will be of three types:

                 1. Those on which no attempt has been made  to  reduce,
                 but which could be chosen for reduction.

                 2. Those on which an attempt to reduce has  been  made,
                 but  which  have  not  yet committed, possibly due to a
                 suspension while awaiting a variable instantiation.

                 3. Those which cannot  be  reduced  as  they  follow  a
                 sequential  "&",  and  the  goal before the "&" has not
                 completed execution.

            The standard display only prints  goals  of  the  first  two
            sorts,  numbering  each  goal. The full display prints every
            goal and includes the bracketing  to  indicate  the  mix  of
            sequential and parallel execution.

            Following the investigate goals  command,  g,  the  list  of
            goals is displayed and the user may choose to investigate it
            in more detail. The system gives the following prompt:

                Enter goal number (0 to restart tracing) :


            If an integer greater than 0 is  entered,  the  system  will
            give  further  details  on  the goal with that number. If no
            attempt has been made to reduce the goal, it  will  just  be
            printed.  Otherwise the current state of reduction is given.
            The current state of the guard computation,  and  any  input
            variables  on  which  a possible commitment is suspended are
            given, followed by the subgoals  to  which  the  goal  would
            reduce if commitment were made.  In the case of a sequential
            clause search, clauses which would be tried if  the  current
            commitment cannot be made are displayed.

            If 0 is entered instead of a goal number, the system returns
            to the computation. Alternatively, the list of the goals can
            be redisplayed by entering l, and can be displayed  in  full
            form by entering f.









                                         36





                                                        Reference Manual

            _1_0.  _S_P_M _C_O_M_P_A_T_I_B_I_L_I_T_Y

            SPM [Foster et al. 1986] and Parallel Parlog  are  syntacti-
            cally  very  similar,  and  the  system  predicates  in both
            languages offer much the same functionality.  However,  many
            SPM  builtins  are  not present in Parallel Parlog, but this
            obstacle can be overcome by loading the compatibility  pack-
            age with the command _u_t_i_l(_s_p_m) It contains predicate defini-
            tions for emulating certain SPM predicates  from  six  broad
            categories  :  I/O,  unification,  arithmetic, type testing,
            term manipulation and utilities. The predicates  defined  in
            this package are :

                1) I/O.
                        fcreate/2      fclose/1      fopen/3
                        loutput/1      loutputnl/1   p/1
                        pnl/1          print_term/1  print-term/2
                        read_char/2    write_char/2  load_files/1

                2) Unification.
                        equal/2        unify/2       assign/2

                3) Arithmetic.
                        add/3          div/3         eq/2
                        less/2         lesseq/2      mod/3
                        mul/3          sub/3

                4) Type testing.
                        con/1          list/1        tuple/1

                5) Term manipulation.
                        a_to_s/2                     s_to_a/2
                        list_to_struct/3             struct_to_list/3
                        l_to_i/3                     i_to_l/2
                        sappend/2                    predefined_op/1

                6) Utilities.
                        defined/1      sleep/1



            The SPM file manipulation primitives access/1,  assem/1  and
            edit/3 are not supported.

            In the area of I/O, the get_term/2 and put_term/3 primitives
            for  reading terms to and from a disk are not implemented in
            Parallel Parlog, and  intok/3  and  iowait/2  are  also  not
            available.

            The set/3 and subset/3 all-solution  primitives  are  absent
            from Parallel Parlog, but all of the type testing primitives
            are present (albeit after  _u_t_i_l(_s_p_m)  is  loaded).  However,
            care must be taken when transferring user-defined predicates
            of this sort across from the SPM, since SPM does  not  treat
            [] as an atom while Parallel Parlog does.



                                         37





                                                        Reference Manual

            Parallel Prolog has neither a freeze/2 nor a  melt/2  primi-
            tive,  but  does  offer  copy_term/2 for which they are most
            often used.

            Unavailable control primitives include controlc/0, key/1 and
            space/3.

            Many SPM utilities are absent from Parallel Parlog,  includ-
            ing  date/3,  show_date/0,  time/3, instream/1, load_comp/0,
            sedit/0, sinput/2 and username/1.  In addition,  the  utili-
            ties  for  type  checking, manipulating binary trees and the
            _x_r_e_f program are not supported.   Finally,  Parallel  Parlog
            does  not support any window predicates, although an X based
            window interface is planned for the future.

            Parallel Parlog differs from SPM in having  more  predicates
            for testing types, a set of lexical comparison primitives, a
            module system, a spypoint mechanism, a C and UNIX interface,
            and  statistic  predicates.  In  addition,  Parallel  Parlog
            enables extra operator sets to be defined, and for  commands
            to be included in source files.

            Some SPM programs may need to  be  rewritten  to  take  into
            account  the  nonflat  guard restriction of Parallel Parlog.
            However, transformation techniques  exist  to  do  this  and
            these may be put into future releases.


            _1_1.  _M_A_C_P_A_R_L_O_G _C_O_M_P_A_T_I_B_I_L_I_T_Y

            MacParlog [Conlon and  Gregory  1989]  is  very  similar  to
            Parallel Parlog except in the area of I/O, where it contains
            numerous primitives  for  manipulating  the  Macintosh  user
            interface.

            Some versions of MacParlog can use arithmetic functions from
            MacProlog  [Clark et al. 1987], for such things as transcen-
            dental and exponential calculations.

            In the area of metalevel predicates, MacParlog allows  terms
            to  be  converted  between  ground and hollow versions using
            toground/3 and tohollow/3, and varsin/2  permits  the  vari-
            ables   in   a   term  to  be  accessed.   primitives/1  and
            private_macparlog_names/1 have no  equivalents  in  Parallel
            Parlog.

            I/O in MacParlog is based on _c_h_a_n_n_e_l_s, which are like Paral-
            lel  Parlog _s_t_r_e_a_m_s except that channels can be connected to
            Macintosh windows. MacParlog input can  utilise  the  mouse,
            and  key/0 is available for waiting on input.  gread/3 reads
            terms and returns the variables contained within  them,  but
            is less flexible than read/4 in Parallel Parlog.  skip/1 and
            skip/2 are slightly different in  MacParlog  since  the  'N'
            argument can be a character as well as an integer.

            File  handling   in   MacParlog   utilises   the   Macintosh


                                         38





                                                        Reference Manual

            hierarchical  filing  system  rather  than UNIX directories.
            However, the resulting predicates are still quite similar to
            those  in Parallel Parlog. The main difference is the use of
            file dialogues in create/2, new/3 and old/2 to access a par-
            ticular file on a volume.

            MacParlog has a  number  of  extra  utility  predicates  not
            present   in   Parallel  Parlog;  namely  beep/1,  recall/2,
            remember/2, ticks/1 and time/3.  Also, the language  permits
            deep  guards to be tried in parallel, and so does not impose
            the nonflat guard  restriction  found  in  Parallel  Parlog.
            MacParlog  has  a  number  of window handling primitives and
            dialogue primitives, none of which are available in Parallel
            Parlog.

            Parallel Parlog has primitives for the lexical comparison of
            terms,  for  gathering statistics, and accessing C and UNIX,
            which are not found in MacParlog. Also, MacParlog  does  not
            support  user-defined operator sets, there is no module sys-
            tem, and compiling and loading is done via pull down  menus.
            In  addition,  MacParlog  does  not  allow  commands  to  be
            included in source files.


            _1_2.  _C_H_A_N_G_E_S _B_E_T_W_E_E_N _V_1._0 _A_N_D _V_1._4

            Most  of  the  differences  between  the  first  and  second
            releases  of Parallel Parlog are internal and transparent to
            the user. This section outlines the areas where the user may
            notice the changes.

            As already mentioned, the memory management  is  quite  dif-
            ferent;  in  _V_1._0  the  sizes  of the four main data areas -
            code, heap, argument stack and process stack -  were  deter-
            mined  at  startup time, and controlled by -C, -H, -S and -P
            options. In _V_1._4 each area is made up of a  linked  list  of
            _s_e_g_m_e_n_t_s  or 64Kbyte blocks, which are allocated from a pool
            of segments.  The initial number of  segments  can  be  con-
            trolled  by the -m option, but on machines in which (shared)
            memory is expandable, the system will automatically allocate
            more when needed.

            C predicates can now be executed on any processor if  loaded
            with load_foreign/3, allowing Parlog to control the parallel
            execution of C routines.  Predicates which must only run  on
            the  master processor (e.g. I/O predicates or perhaps window
            predicates)  should  be   loaded   using   load_foreign_io/3
            instead.

            There have been some changes to the compiler and the code it
            generates.   One  noticeable change is that calls to is/2 in
            the body can now be executed inline, with a full  goal  call
            only  being  made  if the inline call cannot proceed because
            input arguments are unbound.  This  optimisation  cannot  be
            done  if  the call to is/2 precedes a sequential conjunction
            operator ("&") and is not in parallel with  any  other  goal


                                         39





                                                        Reference Manual

            calls - the compiler provides a warning message about this.

            The public/1 predicate has been changed so that it makes the
            specified  predicates  visible  in all modules. Before, only
            public predicates in the _s_y_s_t_e_m module were visible  to  all
            modules;  public predicates in other modules still had to be
            explicitly imported.

            There were a few problems related to  the  use  of  floating
            point numbers in _V_1._0 which have been fixed in _V_1._4.


            _1_3.  _B_U_G_S/_F_E_A_T_U_R_E_S

            Suspended guard calls for a candidate clause, which has been
            rejected in favour of another clause, are not removed by the
            system. Such suspended guard  calls  are  also  called  _d_e_a_d
            processes.

            Deadlock and interrupts do not  kill  or  remove  processes;
            they only restart the top level command interpreter.

            I/O predicates produce a segmentation error when called with
            an inappropriate stream argument.

            It is possible to overflow a heap  by  unifying  a  variable
            with  a  very  large term in the source code (e.g. a list of
            over 128 elements) when the top heap segment is almost full.
            This  can result in a segmentation error.  There is no prob-
            lem with terms constructed dynamically during execution  and
            a  workaround  is  to  break  up  the  source code term into
            smaller parts, e.g.

                g(X) <- X = [1,2,....,128|X1], g1(X1).
                g1(X1) <- X1 = [129,130,....,256].


            Similarly, it is possible to overflow an argument  stack  by
            calling  a  large  number of goals in a parallel conjunction
            when the top stack segment is almost full, if the sum of all
            the  arguments  in the parallel conjunction exceeds 256. The
            workaround is to replace some of the goals in  the  conjunc-
            tion  with  a  single  call  to a predicate that invokes the
            replaced goals.  In theory, the compiler could  be  made  to
            detect and fix both of these cases automatically.

            Loading C predicates does not work on the Alliant  and  Mul-
            timax versions.










                                         40





                                                        Reference Manual

            _1_4.  _S_Y_S_T_E_M _P_R_E_D_I_C_A_T_E_S _A_T _A _G_L_A_N_C_E

            Term1? = Term2?  ......   13    clear_input(Stream?)
            Term1? == Term2?  .....   14         ..................   23
            Term1?  \==   Term2?            flush_output(Stream?)
                 ..................   14         ..................   23
            Term1? <= Term2?  .....   14    get0(Stream?,N^) ......   23
            var(X?) ...............   14    get(Stream?,N^) .......   24
            nonvar(X?).  ..........   14    skip(Stream?,N?) ......   24
            ground(X?).  ..........   15    put(Stream?,N?) .......   24
            data(X?).  ............   15    nl(Stream?) ...........   24
            atom(X?) ..............   15    tab(Stream?,N?) .......   24
            atomic(X?) ............   15    get0(N^) ..............   25
            integer(X?) ...........   15    get(N^) ...............   25
            float(X?) .............   15    skip(N?) ..............   25
            number(X?).  ..........   15    put(N?) ...............   25
            Value^  is   Expres-            nl ....................   25
                 sion?  ...........   16    tab(N?) ...............   25
            X?=@=Y?  ..............   17    read(Stream?,Term^)
            X?\=@=Y?  .............   18         ..................   25
            X?@<Y?  ...............   18    read(Stream?,OpSet?,Term^,Vars^)
            X?@>Y?  ...............   18         ..................   25
            X?@=<Y?  ..............   18    display(Stream?,Term?)
            X?@>=Y?  ..............   18         ..................   25
            X?=:=Y?  ..............   18    write(Stream?,Term?)
            X?=\=Y?  ..............   18         ..................   26
            X?<Y?  ................   19    writeq(Stream?,Term?)
            X?>Y?  ................   19         ..................   26
            X?=<Y?  ...............   19    write_canonical(Stream?,Term?)
            X?>=Y?  ...............   19         ..................   26
            name(Atomic?,String?)           read(Term^) ...........   26
                 ..................   19    display(Term?) ........   26
            Term? =.. List?  ......   20    write(Term?) ..........   26
            functor(Term?,Functor?,Arity?)  writeq(Term?) .........   26
                 ..................   20    write_canonical(Term?)
            arg(N?,Term?,Arg^)                   ..................   26
                 ..................   20    compile(File?) ........   26
            copy_term(Term1?,Term2^)        load(File?) ...........   27
                 ..................   20    public Preds?  ........   27
            call(Call?) ...........   20    export(Predicates?)
            Module?#Call?  ........   21         ..................   27
            fail ..................   21    import(Module?,Predicates?)
            not(Call?) ............   21         ..................   27
            halt ..................   21    module(Module?) .......   27
            true ..................   21    current_module(Module^)
            open(File?,Mode?,Stream^)            ..................   28
                 ..................   22    op(OpSet?,Prec?,Type?,Op?)
            close(Stream?) ........   22         ..................   28
            set_input(Stream?)              current_op(OpSet?,Prec^,Type?,Op?)
                 ..................   22         ..................   28
            set_output(Stream?)             op(Prec?,Type?,Op?)
                 ..................   23         ..................   28
            current_input(Stream?)          current_op(Prec^,Type?,Op?)
                 ..................   23         ..................   28
            current_output(Stream?)         util(Package) .........   28
                 ..................   23    statistics(Key?,Val^)


                                         41





                                                        Reference Manual

                 ..................   29
            statistics ............   29
            unix(Command?) ........   29
            load_foreign(Preds?,Obj?,Libs?)
                 ..................   29
            load_foreign(Preds?,Obj?)
                 ..................   29
            load_foreign_io(Preds?,Obj?,Libs?)
                 ..................   30
            load_foreign_io(Preds?,Obj?)
                 ..................   30
            spy(Pred?) ............   30
            nospy(Pred?) ..........   30


            _R_E_F_E_R_E_N_C_E_S

            Clark, K., McCabe, F.G., Johns, N., and Spenser,  C.  1987.,
            _L_P_A _M_a_c_P_R_O_L_O_G _R_e_f_e_r_e_n_c_e _M_a_n_u_a_l, Logic Programming Associates
            Ltd, London.

            Conlon, T., and Gregory, S. 1989., _H_a_n_d_s _o_n  _M_a_c_P_a_r_l_o_g  _1._0,
            Parallel Logic Programming Limited, London, January.

            Crammond, J.A. 1990., _T_h_e _A_b_s_t_r_a_c_t _M_a_c_h_i_n_e  _a_n_d  _I_m_p_l_e_m_e_n_t_a_-
            _t_i_o_n  _o_f  _P_a_r_a_l_l_e_l _P_a_r_l_o_g, Research Report, Dept. of Comput-
            ing, Imperial College, London.

            Foster, I., Gregory, S., Ringwood, G., and Satoh, K.  1986.,
            _A   _S_e_q_u_e_n_t_i_a_l  _I_m_p_l_e_m_e_n_t_a_t_i_o_n  _o_f _P_A_R_L_O_G, 3rd International
            Conference on Logic Programming, London, July.

            Gregory, S. 1987., _P_a_r_a_l_l_e_l _L_o_g_i_c _P_r_o_g_r_a_m_m_i_n_g _i_n   _P_A_R_L_O_G  :
            _T_h_e  _L_a_n_g_u_a_g_e  _a_n_d  _i_t_s  _I_m_p_l_e_m_e_n_t_a_t_i_o_n, Addison-Wesley.
























                                         42



