403 lines
9.0 KiB
Prolog
403 lines
9.0 KiB
Prolog
/*************************************************************************
|
|
* *
|
|
* YAP Prolog *
|
|
* *
|
|
* Yap Prolog was developed at NCCUP - Universidade do Porto *
|
|
* *
|
|
* Copyright L.Damas, V.S.Costa and Universidade do Porto 1985-1997 *
|
|
* *
|
|
**************************************************************************
|
|
* *
|
|
* File: utils.yap *
|
|
* Last rev: 8/2/88 *
|
|
* mods: *
|
|
* comments: Some utility predicates available in yap *
|
|
* *
|
|
*************************************************************************/
|
|
|
|
:- system_module( '$_utils', [callable/1,
|
|
current_op/3,
|
|
nb_current/2,
|
|
nth_instance/3,
|
|
nth_instance/4,
|
|
op/3,
|
|
prolog/0,
|
|
recordaifnot/3,
|
|
recordzifnot/3,
|
|
simple/1,
|
|
subsumes_term/2], ['$getval_exception'/3]).
|
|
|
|
:- use_system_module( '$_boot', ['$live'/0]).
|
|
|
|
:- use_system_module( '$_errors', ['$do_error'/2]).
|
|
|
|
|
|
/** @pred op(+ _P_,+ _T_,+ _A_) is iso
|
|
|
|
|
|
Defines the operator _A_ or the list of operators _A_ with type
|
|
_T_ (which must be one of `xfx`, `xfy`,`yfx`,
|
|
`xf`, `yf`, `fx` or `fy`) and precedence _P_
|
|
(see appendix iv for a list of predefined operators).
|
|
|
|
Note that if there is a preexisting operator with the same name and
|
|
type, this operator will be discarded. Also, `,` may not be defined
|
|
as an operator, and it is not allowed to have the same for an infix and
|
|
a postfix operator.
|
|
|
|
|
|
*/
|
|
op(P,T,V) :-
|
|
'$check_op'(P,T,V,op(P,T,V)),
|
|
'$op'(P, T, V).
|
|
|
|
% just check the operator declarations for correctness.
|
|
'$check_op'(P,T,Op,G) :-
|
|
( var(P) ; var(T); var(Op)), !,
|
|
'$do_error'(instantiation_error,G).
|
|
'$check_op'(P,_,_,G) :-
|
|
\+ integer(P), !,
|
|
'$do_error'(type_error(integer,P),G).
|
|
'$check_op'(P,_,_,G) :-
|
|
P < 0, !,
|
|
'$do_error'(domain_error(operator_priority,P),G).
|
|
'$check_op'(_,T,_,G) :-
|
|
\+ atom(T), !,
|
|
'$do_error'(type_error(atom,T),G).
|
|
'$check_op'(_,T,_,G) :-
|
|
\+ '$associativity'(T), !,
|
|
'$do_error'(domain_error(operator_specifier,T),G).
|
|
'$check_op'(P,T,V,G) :-
|
|
'$check_module_for_op'(V, G, NV),
|
|
'$check_top_op'(P, T, NV, G).
|
|
|
|
'$check_top_op'(_, _, [], _) :- !.
|
|
'$check_top_op'(P, T, [Op|NV], G) :- !,
|
|
'$check_ops'(P, T, [Op|NV], G).
|
|
'$check_top_op'(P, T, V, G) :-
|
|
atom(V), !,
|
|
'$check_op_name'(P, T, V, G).
|
|
'$check_top_op'(_P, _T, V, G) :-
|
|
'$do_error'(type_error(atom,V),G).
|
|
|
|
'$associativity'(xfx).
|
|
'$associativity'(xfy).
|
|
'$associativity'(yfx).
|
|
'$associativity'(yfy).
|
|
'$associativity'(xf).
|
|
'$associativity'(yf).
|
|
'$associativity'(fx).
|
|
'$associativity'(fy).
|
|
|
|
'$check_module_for_op'(MOp, G, _) :-
|
|
var(MOp), !,
|
|
'$do_error'(instantiation_error,G).
|
|
'$check_module_for_op'(M:_V, G, _) :-
|
|
var(M), !,
|
|
'$do_error'(instantiation_error,G).
|
|
'$check_module_for_op'(M:V, G, NV) :-
|
|
atom(M), !,
|
|
'$check_module_for_op'(V, G, NV).
|
|
'$check_module_for_op'(M:_V, G, _) :- !,
|
|
'$do_error'(type_error(atom,M),G).
|
|
'$check_module_for_op'(V, _G, V).
|
|
|
|
'$check_ops'(_P, _T, [], _G) :- !.
|
|
'$check_ops'(P, T, [Op|NV], G) :- !,
|
|
(
|
|
var(NV)
|
|
->
|
|
'$do_error'(instantiation_error,G)
|
|
;
|
|
'$check_module_for_op'(Op, G, NOp),
|
|
'$check_op_name'(P, T, NOp, G),
|
|
'$check_ops'(P, T, NV, G)
|
|
).
|
|
'$check_ops'(_P, _T, Ops, G) :-
|
|
'$do_error'(type_error(list,Ops),G).
|
|
|
|
'$check_op_name'(_,_,V,G) :-
|
|
var(V), !,
|
|
'$do_error'(instantiation_error,G).
|
|
'$check_op_name'(_,_,',',G) :- !,
|
|
'$do_error'(permission_error(modify,operator,','),G).
|
|
'$check_op_name'(_,_,'[]',G) :- T \= yf, T\= xf, !,
|
|
'$do_error'(permission_error(create,operator,'[]'),G).
|
|
'$check_op_name'(_,_,'{}',G) :- T \= yf, T\= xf, !,
|
|
'$do_error'(permission_error(create,operator,'{}'),G).
|
|
'$check_op_name'(P,T,'|',G) :-
|
|
(
|
|
integer(P),
|
|
P < 1001, P > 0
|
|
;
|
|
atom_codes(T,[_,_])
|
|
), !,
|
|
'$do_error'(permission_error(create,operator,'|'),G).
|
|
'$check_op_name'(_,_,V,_) :-
|
|
atom(V), !.
|
|
'$check_op_name'(_,_,A,G) :-
|
|
'$do_error'(type_error(atom,A),G).
|
|
|
|
'$op'(P, T, ML) :-
|
|
strip_module(ML, M, [A|As]), !,
|
|
'$opl'(P, T, M, [A|As]).
|
|
'$op'(P, T, A) :-
|
|
'$op2'(P,T,A).
|
|
|
|
'$opl'(_P, _T, _, []).
|
|
'$opl'(P, T, M, [A|As]) :-
|
|
'$op2'(P, T, M:A),
|
|
'$opl'(P, T, M, As).
|
|
|
|
'$op2'(P,T,A) :-
|
|
atom(A), !,
|
|
'$opdec'(P,T,A,prolog).
|
|
'$op2'(P,T,A) :-
|
|
strip_module(A,M,N),
|
|
'$opdec'(P,T,N,M).
|
|
|
|
/** @pred current_op( _P_, _T_, _F_) is iso
|
|
|
|
|
|
Defines the relation: _P_ is a currently defined operator of type
|
|
_T_ and precedence _P_.
|
|
|
|
|
|
*/
|
|
current_op(X,Y,V) :- var(V), !,
|
|
'$current_module'(M),
|
|
'$do_current_op'(X,Y,V,M).
|
|
current_op(X,Y,M:Z) :- !,
|
|
'$current_opm'(X,Y,Z,M).
|
|
current_op(X,Y,Z) :-
|
|
'$current_module'(M),
|
|
'$do_current_op'(X,Y,Z,M).
|
|
|
|
|
|
'$current_opm'(X,Y,Z,M) :-
|
|
nonvar(Y),
|
|
\+ '$associativity'(Y),
|
|
'$do_error'(domain_error(operator_specifier,Y),current_op(X,Y,M:Z)).
|
|
'$current_opm'(X,Y,Z,M) :-
|
|
var(Z), !,
|
|
'$do_current_op'(X,Y,Z,M).
|
|
'$current_opm'(X,Y,M:Z,_) :- !,
|
|
'$current_opm'(X,Y,Z,M).
|
|
'$current_opm'(X,Y,Z,M) :-
|
|
'$do_current_op'(X,Y,Z,M).
|
|
|
|
'$do_current_op'(X,Y,Z,M) :-
|
|
nonvar(Y),
|
|
\+ '$associativity'(Y),
|
|
'$do_error'(domain_error(operator_specifier,Y),current_op(X,Y,M:Z)).
|
|
'$do_current_op'(X,Y,Z,M) :-
|
|
atom(Z), !,
|
|
'$current_atom_op'(Z, M1, Prefix, Infix, Posfix),
|
|
( M1 = prolog -> true ; M1 = M ),
|
|
(
|
|
'$get_prefix'(Prefix, X, Y)
|
|
;
|
|
'$get_infix'(Infix, X, Y)
|
|
;
|
|
'$get_posfix'(Posfix, X, Y)
|
|
).
|
|
'$do_current_op'(X,Y,Z,M) :-
|
|
'$current_op'(Z, M1, Prefix, Infix, Posfix),
|
|
( M1 = prolog -> true ; M1 = M ),
|
|
(
|
|
'$get_prefix'(Prefix, X, Y)
|
|
;
|
|
'$get_infix'(Infix, X, Y)
|
|
;
|
|
'$get_posfix'(Posfix, X, Y)
|
|
).
|
|
|
|
'$get_prefix'(Prefix, X, Y) :-
|
|
Prefix > 0,
|
|
X is Prefix /\ 0xfff,
|
|
(
|
|
0x2000 /\ Prefix =:= 0x2000
|
|
->
|
|
Y = fx
|
|
;
|
|
Y = fy
|
|
).
|
|
|
|
'$get_infix'(Infix, X, Y) :-
|
|
Infix > 0,
|
|
X is Infix /\ 0xfff,
|
|
(
|
|
0x3000 /\ Infix =:= 0x3000
|
|
->
|
|
Y = xfx
|
|
;
|
|
0x1000 /\ Infix =:= 0x1000
|
|
->
|
|
Y = xfy
|
|
;
|
|
Y = yfx
|
|
).
|
|
|
|
'$get_posfix'(Posfix, X, Y) :-
|
|
Posfix > 0,
|
|
X is Posfix /\ 0xfff,
|
|
(
|
|
0x1000 /\ Posfix =:= 0x1000
|
|
->
|
|
Y = xf
|
|
;
|
|
Y = yf
|
|
).
|
|
|
|
|
|
prolog :-
|
|
'$live'.
|
|
|
|
%%% current ....
|
|
|
|
/** @pred recordaifnot(+ _K_, _T_,- _R_)
|
|
|
|
|
|
If a term equal to _T_ up to variable renaming is stored under key
|
|
_K_ fail. Otherwise, make term _T_ the first record under key
|
|
_K_ and unify _R_ with its reference.
|
|
|
|
|
|
*/
|
|
recordaifnot(K,T,R) :-
|
|
recorded(K,T,R), % force non-det binding to R.
|
|
'$still_variant'(R,T),
|
|
!,
|
|
fail.
|
|
recordaifnot(K,T,R) :-
|
|
recorda(K,T,R).
|
|
|
|
/** @pred recordzifnot(+ _K_, _T_,- _R_)
|
|
|
|
|
|
If a term equal to _T_ up to variable renaming is stored under key
|
|
_K_ fail. Otherwise, make term _T_ the first record under key
|
|
_K_ and unify _R_ with its reference.
|
|
|
|
This predicate is YAP specific.
|
|
|
|
|
|
*/
|
|
recordzifnot(K,T,R) :-
|
|
recorded(K,T,R),
|
|
'$still_variant'(R,T),
|
|
!,
|
|
fail.
|
|
recordzifnot(K,T,R) :-
|
|
recordz(K,T,R).
|
|
|
|
/** @pred callable( _T_) is iso
|
|
|
|
|
|
Checks whether _T_ is a callable term, that is, an atom or a
|
|
compound term.
|
|
|
|
|
|
*/
|
|
callable(A) :-
|
|
( var(A) -> fail ; number(A) -> fail ; true ).
|
|
|
|
/** @pred simple( _T_)
|
|
|
|
|
|
Checks whether _T_ is unbound, an atom, or a number.
|
|
|
|
|
|
*/
|
|
simple(V) :- var(V), !.
|
|
simple(A) :- atom(A), !.
|
|
simple(N) :- number(N).
|
|
|
|
/** @pred nth_instance(? _Key_,? _Index_,? _R_)
|
|
|
|
|
|
Fetches the _Index_nth entry in the internal database under the key
|
|
_Key_. Entries are numbered from one. If the key _Key_ or the
|
|
_Index_ are bound, a reference is unified with _R_. Otherwise,
|
|
the reference _R_ must be given, and YAP will find
|
|
the matching key and index.
|
|
|
|
|
|
*/
|
|
nth_instance(Key,Index,Ref) :-
|
|
nonvar(Key), var(Index), var(Ref), !,
|
|
recorded(Key,_,Ref),
|
|
'$nth_instance'(_,Index,Ref).
|
|
nth_instance(Key,Index,Ref) :-
|
|
'$nth_instance'(Key,Index,Ref).
|
|
|
|
/** @pred nth_instance(? _Key_,? _Index_, _T_,? _R_)
|
|
|
|
Fetches the _Index_nth entry in the internal database under the key
|
|
_Key_. Entries are numbered from one. If the key _Key_ or the
|
|
_Index_ are bound, a reference is unified with _R_. Otherwise,
|
|
the reference _R_ must be given, and YAP will find
|
|
the matching key and index.
|
|
|
|
|
|
*/
|
|
nth_instance(Key,Index,T,Ref) :-
|
|
nonvar(Key), var(Index), var(Ref), !,
|
|
recorded(Key,T,Ref),
|
|
'$nth_instance'(_,Index,Ref).
|
|
nth_instance(Key,Index,T,Ref) :-
|
|
'$nth_instance'(Key,Index,Ref),
|
|
instance(Ref,T).
|
|
|
|
/** @pred nb_current(? _Name_, ? _Value_)
|
|
|
|
|
|
Enumerate all defined variables with their value. The order of
|
|
enumeration is undefined.
|
|
|
|
|
|
*/
|
|
/** @pred nb_current(? _Name_,? _Value_)
|
|
|
|
|
|
Enumerate all defined variables with their value. The order of
|
|
enumeration is undefined.
|
|
|
|
|
|
*/
|
|
nb_current(GlobalVariable, Val) :-
|
|
'$nb_current'(GlobalVariable),
|
|
'$nb_getval'(GlobalVariable, Val, _).
|
|
|
|
'$getval_exception'(GlobalVariable, _Val, Caller) :-
|
|
user:exception(undefined_global_variable, GlobalVariable, Action),
|
|
!,
|
|
(
|
|
Action == fail
|
|
->
|
|
fail
|
|
;
|
|
Action == retry
|
|
->
|
|
true
|
|
;
|
|
Action == error
|
|
->
|
|
'$do_error'(existence_error(variable, GlobalVariable),Caller)
|
|
;
|
|
'$do_error'(type_error(atom, Action),Caller)
|
|
).
|
|
|
|
|
|
/** @pred subsumes_term(? _Subsumer_, ? _Subsumed_)
|
|
|
|
|
|
|
|
Succeed if _Submuser_ subsumes _Subsuned_ but does not bind any
|
|
variable in _Subsumer_.
|
|
|
|
|
|
*/
|
|
subsumes_term(A,B) :-
|
|
\+ \+ terms:subsumes(A,B).
|