This repository has been archived on 2023-08-20. You can view files and clone it, but cannot push or open issues or pull requests.
yap-6.3/pl/builtins.yap

347 lines
7.2 KiB
Prolog

/*************************************************************************
* *
* YAP Prolog *
* *
* Yap Prolog was developed at NCCUP - Universidade do Porto *
* *
* Copyright L.Damas, V.S.Costa and Universidade do Porto 1985-2014 *
* *
**************************************************************************
* *
* File: boot.yap *
* Last rev: 8/2/88 *
* mods: *
* commen ts: boot file for Prolog *
* *
*************************************************************************/
/**
@file boot.yap
@brief YAP bootstrap
@addtogroup YAPControl Control Predicates
@ingroup builtins
@{
*/
/** @pred 0:P,0:Q is iso, meta
Conjunction of goals (and).
The conjunction is a fundamental construct of Prolog. Example:
~~~~~~~
p(X) :- q(X), r(X).
~~~~~~~
should be read as `p( _X_) if q( _X_) and r( _X_).
*/
','(X,Y) :-
yap_hacks:env_choice_point(CP),
'$current_module'(M),
'$call'(X,CP,(X,Y),M),
'$call'(Y,CP,(X,Y),M).
/** @pred 0:P ; 0:Q is iso
Disjunction of goals (or).
Example:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
p(X) :- q(X); r(X).
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
should be read as "p( _X_) if q( _X_) or r( _X_)".
*/
';'((X->A),Y) :- !,
yap_hacks:env_choice_point(CP),
'$current_module'(M),
( '$execute'(X)
->
'$call'(A,CP,(X->A;Y),M)
;
'$call'(Y,CP,(X->A;Y),M)
).
';'((X*->A),Y) :- !,
yap_hacks:env_choice_point(CP),
'$current_module'(M),
(
'$current_choice_point'(DCP),
'$execute'(X),
yap_hacks:cut_at(DCP),
'$call'(A,CP,((X*->A),Y),M)
;
'$call'(Y,CP,((X*->A),Y),M)
).
';'(X,Y) :-
yap_hacks:env_choice_point(CP),
'$current_module'(M),
( '$call'(X,CP,(X;Y),M) ; '$call'(Y,CP,(X;Y),M) ).
'|'(X,Y) :-
yap_hacks:env_choice_point(CP),
'$current_module'(M),
( '$call'(X,CP,(X|Y),M) ; '$call'(Y,CP,(X|Y),M) ).
/** @pred 0:Condition -> 0:Action is iso
@short If _Condition__ has a solution, call _Action_;
@long
Read as "if-then-else" or "commit". This operator is similar to the
conditional operator of imperative languages and can be used alone or
with an else part as follows:
~~~~~
+P -> +Q
~~~~~
"if P then Q".
~~~~~
+P -> +Q; +R
~~~~~
"if P then Q else R".
These two predicates could be defined respectively in Prolog as:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
(P -> Q) :- P, !, Q.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
and
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
(P -> Q; R) :- P, !, Q.
(P -> Q; R) :- R.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if there were no "cuts" in _P_, _Q_ and _R_.
vNote that the commit operator works by "cutting" any alternative
solutions of _P_.
Note also that you can use chains of commit operators like:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
P -> Q ; R -> S ; T.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Note that `(->)/2` does not affect the scope of cuts in its
arguments.
*/
'->'(X,Y) :-
yap_hacks:env_choice_point(CP),
'$current_module'(M),
( '$call'(X,CP,(X->Y),M) -> '$call'(Y,CP,(X->Y),M) ).
/** @pred 0:Condition *-> 0:Action is iso
This construct implements the so-called <em>soft-cut</em>. The control is
defined as follows:
+ If _Condition_ succeeds at least once, the
semantics is the same as ( _Condition_, _Action_).
+ If
_Condition_ does not succeed, the semantics is that of (\\+
_Condition_, _Else_).
In other words, if _Condition_
succeeds at least once, simply behave as the conjunction of
_Condition_ and _Action_, otherwise execute _Else_.
The construct _A *-> B_, i.e. without an _Else_ branch, is
translated as the normal conjunction _A_, _B_.
*/
'*->'(X,Y) :-
yap_hacks:env_choice_point(CP),
'$current_module'(M),
( '$call'(X,CP,(X*->Y),M), '$call'(Y,CP,(X*->Y),M) ).
/** @pred ! is iso
Read as "cut". Cuts any choices taken in the current procedure.
When first found "cut" succeeds as a goal, but if backtracking should
later return to it, the parent goal (the one which matches the head of
the clause containing the "cut", causing the clause activation) will
fail. This is an extra-logical predicate and cannot be explained in
terms of the declarative semantics of Prolog.
example:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
member(X,[X|_]).
member(X,[_|L]) :- member(X,L).
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
With the above definition
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
?- member(X,[1,2,3]).
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
will return each element of the list by backtracking. With the following
definition:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
member(X,[X|_]) :- !.
member(X,[_|L]) :- member(X,L).
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
the same query would return only the first element of the
list, since backtracking could not "pass through" the cut.
*/
! :-
yap_hacks:parent_choice_point(CP),
yap_hacks:cut_at(CP).
/** @pred \+ 0:P is iso, meta
Negation by failure.
Goal _P_ is not provable. The execution of this predicate fails if
and only if the goal _P_ finitely succeeds. It is not a true logical
negation, which is impossible in standard Prolog, but
"negation-by-failure".
This predicate might be defined as:
~~~~~~~~~~~~
\+(P) :- P, !, fail.
\+(_).
~~~~~~~~~~~~
if _P_ did not include "cuts".
If _P_ includes cuts, the cuts are defined to be scoped by _P_: they cannot cut over the calling prredicate.
~~~~~~~~~~~~
go(P).
:- \+ P, !, fail.
\+(_).
~~~~~~~~~~~~
*/
\+(G) :- \+ '$execute'(G).
not(G) :- \+ '$execute'(G).
/** @pred repeat is iso
Succeeds repeatedly.
In the next example, `repeat` is used as an efficient way to implement
a loop. The next example reads all terms in a file:
~~~~~~~~~~~~~{.prolog}
a :- repeat, read(X), write(X), nl, X=end_of_file, !.
~~~~~~~~~~~~~
the loop is effectively terminated by the cut-goal, when the test-goal
`X=end` succeeds. While the test fails, the goals `read(X)`,
`write(X)`, and `nl` are executed repeatedly, because
backtracking is caught by the `repeat` goal.
The built-in `repeat/0` could be defined in Prolog by:
~~~~~{.prolog}
repeat.
repeat :- repeat.
~~~~~
The predicate between/3 can be used to iterate for a pre-defined
number of steps.
*/
repeat :- '$repeat'.
'$repeat'.
'$repeat'.
'$repeat'.
'$repeat'.
'$repeat'.
'$repeat'.
'$repeat'.
'$repeat'.
'$repeat'.
'$repeat' :- '$repeat'.
/** @pred + _P_ is nondet
The same as `call( _P_)`. This feature has been kept to provide
compatibility with C-Prolog. When compiling a goal, YAP
generates a `call( _X_)` whenever a variable _X_ is found as
a goal.
~~~~~{.prolog}
a(X) :- X.
~~~~~
is converted to:
~~~~~{.prolog}
a(X) :- call(X).
~~~~~
*/
/** @pred call( 0:P ) is iso
Meta-call predicate.
If _P_ is instantiated to an atom or a compound term, the goal `call(
_P_)` is executed as if the clause was originally written as _P_
instead as call( _P_ ), except that any "cut" occurring in _P_ only
cuts alternatives in the execution of _P_.
*/
call(G) :- '$execute'(G).
/** @pred incore( 0:P )
same as call/1.
*/
/** @pred once( 0 G) is iso
Execute the goal _G_ only once. The predicate is defined by:
~~~~~{.prolog}
once(G) :- call(G), !.
~~~~~
Note that cuts inside once/1 can only cut the other goals inside
once/1.
*/
once(G) :-
strip_module(G, M, C),
'$meta_call'(C, M),
!.
(:- G) :- '$execute'(G), !.
(?- G) :- '$execute'(G).
'$$!'(CP) :- '$cut_by'(CP).
[] :- true.
%% @}