! all 0 0 0 100400 797 ` /* all: Load all the current bits of the standard Prolog system Fernando Pereira Updated: 17 September 83 */ :-([ 'cplog:tty', % tty* predicates 'cplog:error', % $error and $message 'cplog:arith', % arithmetic expression flattener 'cplog:grammar', % DCG grammar rule translation 'cplog:sort', % sort, keysort, merge, msort 'cplog:setof', % setof, bagof, ^ 'cplog:tracing', % Debugging evaluable predicates 'cplog:listing', % Listing and other output 'cplog:ops', % Operator declaration/lookup 'cplog:ground', % numbervars/ground 'cplog:unify', % unify/occurs_check 'cplog:lib' % lib/libdirectory ]). :-([ 'cplog:protect' % Lock things up ]). arith 0 0 0 100400 3446 ` % File : pl/arith % Author : Fernando Pereira % Updated: 18 November 1983 % Purpose: Preprocess arithmetic expressions. /* The point of all this junk is that C Prolog normally doesn't do anything special with arithmetic, so that in a goal such as X is Y+1 C Prolog says to itself "Aha! Y occurs inside a structure inside an argument, I must make it a GLOBAL variable!" The trouble with global variables is that they don't go away until you fail, so a simple little program which does a lot of computing may tie up enormous amounts of global stack it doesn't really need. One cure for this would be to provide a garbage collector. Joking aside, this file cures the problem by translating arithmetic goals into calls on is/3 and is/4. But only if the $carith flag is on. Beware! "X is Y" identifies X and Y at compile time!!!!!! I have made the expansion simplify lists and evaluate constants as well, so (Up is Lo+("a"-"A")) => is(Up, +, Lo, 32). */ $compile_arith(P0, P) :- $carith(1, 1), !, $expand_arith(P0, P). $compile_arith(P, P). $expand_arith(P, P) :- var(P), !. $expand_arith((P0,Q0), (P,Q)) :- !, $expand_arith(P0, P), $expand_arith(Q0, Q). $expand_arith((P0;Q0), (P;Q)) :- !, $expand_arith(P0, P), $expand_arith(Q0, Q). $expand_arith((P0->Q0), (P;Q)) :- !, $expand_arith(P0, P), $expand_arith(Q0, Q). $expand_arith(X is Y, P) :- nonvar(Y), % Don't bother rewriting simple expressions. \+ atomic(Y), % In fact we mustn't rewrite variables. !, $user_call(expand_expression(Y, P0, X0)), $drop_is(X0, X, P1), and(P0, P1, P). $expand_arith(Comp0, R) :- $compop(Comp0, Op, E, F), !, $compop(Comp, Op, U, V), $user_call(expand_expression(E, P, U)), $user_call(expand_expression(F, Q, V)), and(P, Q, R0), and(R0, Comp, R). $expand_arith(P, P). and(true, P, P) :- !. and(P, true, P) :- !. and(P, Q, (P,Q)). $drop_is(V, V, true) :- var(V), !. $drop_is(V, X, X is V). $compop(X < Y, < , X, Y). $compop(X > Y, > , X, Y). $compop(X=< Y,=< , X, Y). $compop(X >=Y, >=, X, Y). $compop(X=:=Y,=:=, X, Y). $compop(X=\=Y,=\=, X, Y). expand_expression(V, true, V) :- var(V), !. expand_expression([T], P, V) :- !, expand_expression(T, P, V). expand_expression(A, true, A) :- atomic(A), !. expand_expression(T, P, V) :- unaryop(T, O, A), !, expand_expression(A, Q, X), expand_expression(V, O, X, Q, P). expand_expression(T, P, V) :- binaryop(T, O, A, B), !, expand_expression(A, Q, X), expand_expression(B, R, Y), expand_expression(V, O, X, Y, Q, P), and(Q, S, P). expand_expression(Y, O, X, Q, Q) :- number(X), !, is(Y, O, X). expand_expression(V, O, X, Q, P) :- and(Q, is(V,O,X), P). expand_expression(Z, O, X, Y, Q, Q) :- number(X), number(Y), !, is(Z, O, X, Y). expand_expression(Z, O, X, Y, Q, P) :- and(Q, is(V,O,X,Y), P). unaryop(+X, +, X). unaryop(-X, -, X). unaryop(\X, \, X). unaryop(exp(X),exp, X). unaryop(log(X),log, X). unaryop(log10(X),log10,X). unaryop(sqrt(X), sqrt, X). unaryop(sin(X),sin, X). unaryop(cos(X),cos, X). unaryop(tan(X),tan, X). unaryop(asin(X), asin, X). unaryop(acos(X), acos, X). unaryop(atan(X), atan, X). unaryop(floor(X),floor,X). binaryop(X+Y, +, X,Y). binaryop(X-Y, -, X,Y). binaryop(X*Y, *, X,Y). binaryop(X/Y, /, X,Y). binaryop(X mod Y, mod, X,Y). binaryop(X//Y, //, X,Y). binaryop(X/\Y, /\, X,Y). binaryop(X\/Y, \/, X,Y). binaryop(X<>Y, >>, X,Y). binaryop(X^Y, ^, X,Y). error 0 0 0 100400 1013 ` /* File : pl/error Author : Richard O'Keefe Updated: 17 September 83, 1983, 7:42:14 pm Purpose: display error messages at the terminal. This is just the beginning of a better error handling system. $error(Message, Culprit) writes an error Message on the "user" stream, and prints the Culprit. On UNIX, we really should have an "error" stream that these messages can be sent to, and the tracing messages should also go there. In practice, "user" will serve. Some errors should cause aborts, some failures, and some ought to switch debugging on. This needs thinking about. The culprits used to be 'print'ed, they are now 'write'n. I really have not the least idea which is better. */ $error(Message, Culprit) :- telling(Old, user), write(' ! '), write(Message), write(' ! goal: '), write(Culprit), nl, tell(Old), !, fail. $message(Message, Culprit) :- telling(Old, user), nl, write(Message), write(Culprit), nl, tell(Old), !. flag 0 0 0 100400 2419 ` /* flag(Variable, OldValue, NewValue) is an omnium-gatherum predicate used to replace a number of old system predicates for switching miscellaneous things on and off. It may also be used for switching your own variables on and off as well. The OldValue is unified with the current value of the Variable, then the NewValue (which must be an arithmetic expression) is evaluated, and assigned to the Variable. This is not a very "logical" operation, I am afraid, but there it is. $flag/3 is the genuine primitive. */ flag(Char, Old, New) :- integer(Char), ( Char < 0 | Char > 127 ), !, $error('first argument is not an Ascii character', flag(Char,Old,New)). flag(Char, Old, New) :- integer(Char), !, $flag(Char, Old, New). flag(Flag, Old, New), var(Flag), !, $error('first argument is a variable', flag(Flag,Old,New)). flag(Flag, Old, New) :- $flag(Flag, Code), !, $flag(Code, Old, New). flag(User, Old, New) :- clause(flag(User, Old), true, Ref), Val is New, !, asserta(flag(User, Val)), erase(Ref). flag(Dud, Old, New) :- $error('no flag/2 fact or bad new value', flag(Dud,Old,New)). % table of system flags and their codes $flag(recons, 128). % consulting/reconsulting? $flag('LC', 129). % capitals start atoms/variables? $flag(fileerrors, 130). % file problems fail/error? $flag(unknown, 131). % undefined preds fail/error? $flag(trace, 132). % tracing/quiet? $flag(debug, 133). % debug info kept/discarded? $flag(leash, 134). % stop at which ports? $flag(all_float, 135). % force floating arithmetic? % specialised predicates for compatibility with Dec-10 Prolog and older % versions of C Prolog. trace :- $flag(132, _, 1), $flag(133, _, 1). 'NOLC' :- $flag(129, _, 0). 'LC' :- $flag(129, _, 1). fileerrors :- $flag(130, _, 0). nofileerrors :- $flag(130, _, 1). all_float(X, Y) :- $flag(135, X0, X0), $flag_code(X0, all_float, X), nonvar(Y), $flag_code(Y0, all_float, Y), $flag(135, X0, Y0). unknown(X, Y) :- $flag(131, X0, X0), $flag_code(X0, unknown, X), nonvar(Y), $flag_code(Y0, unknown, Y), $flag(131, X0, Y0). $flag_code(1, all_float, on). $flag_code(0, all_float, off). $flag_code(1, unknown, trace). $flag_code(0, unknown, fail). % temporary predicates to be unfolded in-line $leash(P, N) :- $flag(134, P, N). $debug(P, N) :- $flag(133, P, N). $recons(X) :- $flag(128, _, X). grammar 0 0 0 100400 1399 ` /* File : pl/grammar Author : Fernando Pereira Updated: Wednesday May 11th, 1983, 7:29:05 pm Purpose: translation of grammar rules */ $translate_rule((LP-->[]), H) :- !, $t_head(LP, S, S, H). $translate_rule((LP-->RP), (H:-B)):- $t_head(LP, S, SR, H), $t_body(RP, S, SR, B1), $t_tidy(B1, B). $t_head((LP,List), S, SR, H):- !, $append(List, SR, List2), $extend([S,List2], LP, H). $t_head(LP, S, SR, H) :- $extend([S,SR], LP, H). $t_body(!, S, S, !) :- !. $t_body([], S, S1, S=S1) :- !. $t_body([X], S, SR, 'C'(S,X,SR)) :- !. $t_body([X|R], S, SR, ('C'(S,X,SR1),RB)) :- !, $t_body(R, SR1, SR, RB). $t_body({T}, S, S, T) :- !. $t_body((T,R), S, SR, (Tt,Rt)) :- !, $t_body(T, S, SR1, Tt), $t_body(R, SR1, SR, Rt). $t_body((T;R), S, SR, (Tt;Rt)) :- !, $t_body(T, S, S1, T1), $t_fill(S, SR, S1, T1, Tt), $t_body(R, S, S2, R1), $t_fill(S, SR, S2, R1, Rt). $t_body(T, S, SR, Tt) :- $extend([S,SR], T, Tt). $t_fill(S, SR, S1, T, (T,SR=S)) :- S1 == S, !. $t_fill(S, SR, SR, T, T). $extend(More, OldT, NewT) :- OldT =.. OldL, $append(OldL, More, NewL), NewT =.. NewL. $append([], L, L) :- !. $append([H|T], L, [H|R]) :- $append(T, L, R). $t_tidy((P1;P2), (Q1;Q2)) :- !, $t_tidy(P1, Q1), $t_tidy(P2, Q2). $t_tidy(((P1,P2),P3), Q) :- $t_tidy((P1,(P2,P3)), Q). $t_tidy((P1,P2), (Q1,Q2)) :- !, $t_tidy(P1, Q1), $t_tidy(P2, Q2). $t_tidy(A, A). 'C'([X|S],X,S). ground 0 0 0 100400 3146 ` /* File : /pl/ground Author : R.A.O'Keefe Updated: 17 September 83 Purpose: define the numbervars/3 and ground/1 predicate. numbervars(Term, Init, Final) is mainly used to make terms ground. The type system in particular needs it so that it can use unification to peform a subsumption test. If the Init argument is 0, the Final argument is the number of distinct variables in the Term. A fairly common way of using this is to achieve one-way pattern matching. By binding all the variables in this term to $VAR(N) terms, we ensure that they cannot be bound again. The trouble is, at the end of the day, we want these bindings to go away as well. So we have to fail, even when we might have succeeded. This leads to a structure similar to that of negation: one_way(Term, ...) :- not not_one_way(Term, ...). not_one_way(Term, ...) :- numbervars(Term, 0, _), good_outcome(......), !, fail. not_one_way(Term, ...). One arrives at this pattern by thinking about the effect of backtracking in a positive procedural sort of way, and it is very definitely not the sort of thing a beginner could come up with. It can occasionally be useful to test whether a term is ground, i.e. whether it contains any variables. The obvious way to do it is numbervars(Term,0,0) (if it isn't obvious, my explanation of numbervars is at fault). However, we can make the test in less time and less space by just working from the definnition: a term is ground if it doesn't contain any variables. numbervars and ground are typical of "meta-logical" predicates which examine terms as data-structures. If variables were just another kind of constant (so that they didn't pattern match against the variables in our clauses), these predicates could be ordinary straight-forward logic, which is why we call them "meta-logical" (they are logic at the meta-level). Like Lisp, Prolog puns the meta-level into the object level, which makes for a powerful programming language, but does horrible things to its elegance. For example, meta-logical predicates cannot be type-checked. Our current ideas about type-checking them are based on introducing an explicit meta-level, which gets "compiled" into object-level Prolog *after* type-checking. */ numbervars('$VAR'(M), M, N) :- !, succ(M, N). numbervars(Atomic, M, M) :- atomic(Atomic), !. numbervars(Term, M, N) :- functor(Term, _, Arity), $numbervars(0, Arity, Term, M, N). $numbervars(A, A, _, N, N) :- !. $numbervars(Am, Arity, Term, M, N) :- succ(Am, An), arg(An, Term, Arg), numbervars(Arg, M, K), !, $numbervars(An, Arity, Term, K, N). ground(Term) :- var(Term), !, /* non ground */ fail. /* so fail */ ground(Term) :- atomic(Term), !. /* numbers and atoms are ground */ ground(Term) :- /* compound terms are ground if */ functor(Term, _, Arity),/* all their subterms are ground*/ $ground(Arity, Term). $ground(0, _) :- !. $ground(N, Term) :- succ(M, N), arg(N, Term, ArgN), ground(ArgN), !, $ground(M, Term). init 0 0 0 100400 12975 ` /* File : pl/init Author : Fernando Pereira + R.A.O'Keefe Updated: 20 November 1983 Purpose: Initial boot file for building the Prolog system. */ % Atoms that the code requires '[]'. % this order has CHANGED ','. '{}'. < . = . > . - . ; . % this atom has been ADDED end_of_file. true. user. $yes. $no. $live. $break. % Functors that the code requires call(_). ','(_,_). '{}'(_). '.'(_,_). ':-'(_,_). ':-'(_). $hidden_call(_). % And now we start properly % Predicates are attached to evaluable predicates defined in the % code by one of two methods: % % 1) pred(....) :- N. % 2) :- $sysp(pred(....),N). % % where N is an integer specifying the evaluable predicate; % N is the value of the switch label in "main.c". % The difference between these is that with the first method a % (local) frame will be built which will contain the arguments % to the procedure; whereas in the second case no frame is built. % Set up the Operators :-(op(P,T,A),105). :-(op(1200, fx,[(:-), (?-)])). :- op(1200,xfx,[(:-), (-->)]). :- op(1100,xfy,(';')). :- op(1050,xfy,('->')). :- op(1000,xfy,(',')). :- op( 900, fy,[\+, not, spy, nospy]). :- op( 700,xfx,[=:=, =\=, <, >=, >, =<, is, =..]). :- op( 700,xfx,[ ==, \==, @<, @>=, @>, @=<, =, \=]). :- op( 500,yfx,[+, -, /\, \/]). :- op( 500, fx,[+, -, \]). :- op( 400,yfx,[*, /, //, <<, >>]). :- op( 300,xfx,mod). :- op( 200,xfy,'^'). % And now all the evaluable predicates $sysp(F,N) :- 112. $sysflgs(F,N) :- 113. :- $sysp((A,B), 1). :- $sysp($hidden_call(P),2). $user_call(_) :- 3. % same as call, but restores tracing call(P) :- 4. :- $sysp(!, 5). repeat :- 6. :- $sysp(abort, 7). :- $sysp($call(_), 8). % Various hacky system predicates :- $sysp(halt, 11). % exit Prolog :- $sysp($break(_), 12). :- $sysp($break_start, 13). :- $sysp($break_end, 14). :- $sysp($exit_break, 15). $user_exec(_) :- 16. :- $sysp($repply, 17). fail :- 18. true. X = X. X \= X :- !, fail. X \= Y. not(Goal) :- $user_call(Goal), !, fail. not(Goal). \+(Goal) :- $user_call(Goal), !, fail. \+(Goal). once(Goal) :- call(Goal), !. &(A,B) :- call(A), call(B). (If -> Then; Else) :- !, $cond(If, Then, Else). $cond(If, Then, Else) :- $user_call(If), !, $user_call(Then). $cond(If, Then, Else) :- $user_call(Else). (If -> Then) :- $user_call(If), !, $user_call(Then). (A;B) :- $call(A). (A;B) :- $call(B). /* The following three predicates are known to the system, but may be added to or retracted by the user. So we have to tell "unknown" not to bother about them. Predicate code 0 is of course NULL. */ :- $sysp(libdirectory(_), 0). :- $sysp(portray(_), 0). :- $sysp(term_expansion(_,_), 0). /*----------------------------------------------------------------------+ | | | ARITHMETIC | | | +----------------------------------------------------------------------*/ % nullary operators :- $sysflgs(cputime, 1). :- $sysflgs(heapused, 2). :- $sysflgs(stackused, 3). :- $sysflgs(pi, 4). :- $sysflgs(log2, 5). % unary operators ([_] is a special case) :- $sysflgs(+(A), 1). :- $sysflgs(-(A), 2). :- $sysflgs(\(A), 3). :- $sysflgs(exp(A), 4). :- $sysflgs(log(A), 5). :- $sysflgs(log10(A), 6). :- $sysflgs(sqrt(A), 7). :- $sysflgs(sin(A), 8). :- $sysflgs(cos(A), 9). :- $sysflgs(tan(A), 10). :- $sysflgs(asin(A), 11). :- $sysflgs(acos(A), 12). :- $sysflgs(atan(A), 13). :- $sysflgs(floor(A), 14). :- $sysflgs(float(A), 15). % binary operators :- $sysflgs(A+B, 1). :- $sysflgs(A-B, 2). :- $sysflgs(A*B, 3). :- $sysflgs(A/B, 4). :- $sysflgs(A mod B, 5). :- $sysflgs(A/\B, 6). :- $sysflgs(A\/B, 7). :- $sysflgs(A<>B, 9). :- $sysflgs(A//B, 10). :- $sysflgs(A^B, 11). X =:= Y :- 20. X =\= Y :- 21. X < Y :- 22. X > Y :- 23. X =< Y :- 24. X >= Y :- 25. succ(X,Y) :- 26. is(X,Y) :- 27. is(X,F,A) :- 28. is(X,F,A,B) :- 29. plus(X,Y,Z) :- 117. /*----------------------------------------------------------------------+ | | | META-LOGICAL | | | +----------------------------------------------------------------------*/ var(X) :- 30. nonvar(X) :- 31. integer(X) :- 32. number(X) :- 33. primitive(X) :- 34. db_reference(X) :- 35. atomic(X) :- 36. atom(X) :- 37. $compare(Op,T1,T2,N) :- 19. % new hack compare(Op,T1,T2) :- 39. A == B :- 40. A \== B :- 41. A @< B :- 42. A @> B :- 43. A @=< B :- 44. A @>= B :- 45. name(X,L) :- 46. functor(T,F,N) :- 47. arg(N,T,A) :- 48. X=..L :- 49. /*----------------------------------------------------------------------+ | | | DATA BASE | | Note: C Prolog does not permit integers as data base keys. | | Dec-10 Prolog does, and the lack is rather a nuisance. | | | +----------------------------------------------------------------------*/ assert(C) :- 50. assertz(C) :- 50. asserta(C) :- 51. assert(C,R) :- 52. assertz(C,R) :- 52. asserta(C,R) :- 53. $recordz(_,_,_) :- 54. $recorda(_,_,_) :- 55. $assertr(_) :- 56. instance(R,T) :- 57. erase(R) :- 58. erased(R) :- 59. $clause(_,_,_):- 60. $clause(_,_,_):- 61. $recorded(_,_,_) :- 62. $recorded(_,_,_) :- 63. current_atom(A) :- % This new clause eliminates the nonvar(A), !, % need for a jump to "cut" in the atom(A). % C code. current_atom(A) :- 64. current_atom(A) :- 65. $current_functor(A,N,K,M) :- 66. $current_functor(A,N,K,M) :- 67. abolish(F,N) :- 68. $checkkey(Key) :- ( var(Key) | primitive(Key) % integer/float/dbref ), !, $error('Invalid data base key', Key). $checkkey(_). clause(Head, Body) :- $checkkey(Head), $clause((Head:-Body), Ref, Head). clause(Head, Body, Ref) :- var(Ref), !, $checkkey(Head), $clause((Head:-Body), Ref ,Head). clause(Head, Body, Ref) :- instance(Ref, (Head:-Body)). retract((Head :- Body)) :- !, $checkkey(Head), $clause((Head:-Body), Ref, Head), erase(Ref). retract(Unit) :- $checkkey(Unit), $clause((Unit:-true), Ref, Unit), erase(Ref). retractall(Head) :- % PDP-11 compatibility $checkkey(Head), $clause((Head:-_), Ref, Head), erase(Ref), fail. retractall(_). recorded(K,T,R) :- $checkkey(K), $recorded(T,R,K). recorda(K,T,R) :- $checkkey(K), $recorda(K,T,R). recordz(K,T,R) :- $checkkey(K), $recordz(K,T,R). record(K,T,R) :- $checkkey(K), $recordz(K,T,R). current_functor(A,P) :- % NB: current_functor(1,1) succeeds! nonvar(P), !, functor(P,A,_). current_functor(A,P) :- current_atom(A), $current_functor(A,N,0,0), functor(P,A,N). current_predicate(A,P) :- current_atom(A), $current_functor(A,N,256,2'11100000), functor(P,A,N). /*----------------------------------------------------------------------+ | | | INPUT/OUTPUT | | | +----------------------------------------------------------------------*/ see(F) :- 70. seeing(F) :- 71. seeing(F,G) :- 72. seeing(F,G) :- 98. seen :- 73. tell(F) :- 74. append(F) :- 75. telling(F) :- 76. telling(F,G) :- 77. telling(F,G) :- 99. told :- 78. close(F) :- 79. ttyflush(F) :- 119. % an afterthought ttyflush :- ttyflush(0). read(T) :- 80. read(T,V) :- 97. % an afterthought, drat it! get0(C) :- 81. get(C) :- 82. skip(C) :- 83. current_line_number(F,N) :- 120. current_line_number(N) :- seeing(F), current_line_number(F, N). display(T) :- 84. write(T) :- 85. writeq(T) :- 86. nl :- 87. put(C) :- 88. tab(C) :- 89. $prompt(_) :- 90. exists(user) :- !. exists(F) :- 91. rename(Old,New) :- 92. cd(_) :- 93. sh :- 94. system(S) :- 95. shell(S) :- 95. % PDP-11 compatibility save(F,N) :- 96. save(F) :- save(F,_). fileerrors :- 100. nofileerrors :- 101. 'LC' :- 102. 'NOLC' :- 103. chtype(Char,Old,New) :- 104. %op(P,T,O) :- 105. $is_op(O,K,P,L,R) :- 69. prompt(_,_) :- 106. trace :- 107. $leash(P,N) :- 108. $debug(P,N) :- 109. $flags(F,P,N) :- 110. $all_float(X,Y) :- 111. %$sysp(F,P) :- 112. %$sysflgs(F,N) :- 113. $recons(_) :- 114. $carith(Old,New) :- 115. unknown(Old,New) :- 116. statistics :- 118. % Graphics predicates added by FDC g_colour(C) :- 121. g_offset(X,Y) :- 122. g_enable(C) :- 123. g_plot(X,Y) :- 124. g_line(X1,Y1,X2,Y2) :- 125. g_trapeze(X1,X2,Y1,X3,X4,Y2) :- 126. g_triangle(X1,Y1,X2,Y2,X3,Y3) :- 127. g_fill(X1,Y1,X2,Y2) :- 128. g_clear :- 129. g_mouse(X,Y,B) :- 130. /*----------------------------------------------------------------------+ | | | TOP LEVEL | | | +----------------------------------------------------------------------*/ $live :- % This is the Prolog session goal $cycle(question), % top level (interactive) loop halt. $cycle(question):- prompt(Old, '| '), repeat, $prompt('| ?- '), read(Question, Variables), $interpret(Question, question, Variables), !, prompt(_, Old). $cycle(Status):- prompt(Old, '| '), repeat, read(Clause, Variables), $interpret(Clause, Status, Variables), !, prompt(_, Old). $interpret(Clause, Status, Variables) :- var(Clause), !, $bind(Variables), $error('Clause is a variable', Clause). $interpret(end_of_file, _, _) :- !. $interpret(Clause, Status, Variables):- $directive(Clause, Status, Body, Type), !, prompt(Old, '|: '), $dogoal(Type, Body, Variables), prompt(_, Old), fail. $interpret(Term, Status, Variables):- expand_term(Term, Expanded), $assertr(Expanded, Variables), !, fail. $assertr(Clause, _) :- $assertr(Clause), !. $assertr(Clause, Variables) :- $bind(Variables), $message('! clause: ', Clause). % $bind([N=V,...]) binds all the variables to their names, to give % slightly more attractive error messages. $bind([Name=Name|Rest]) :- !, $bind(Rest). $bind([]). $directive(:-(X), _, X, command ) :- !. $directive(?-(X), _, X, question) :- !. $directive(X, question, X, question). $dogoal(command, Command, Variables) :- $user_exec(Command), !. $dogoal(command, Culprit, Variables) :- !, % should print the culprit $bind(Variables), $message('? ', Culprit). $dogoal(question, Question, Variables) :- $user_exec(Question), telling(Old, user), ($repply(Variables, Variables), tell(Old) ; tell(Old), fail), !. $dogoal(question, _, _) :- telling(Old, user), nl, write(no), nl, tell(Old), !. % $repply/2 (and hence $repply/0) is only executed when output is % directed to 'user'. If you do :- tell(foo), [baz], told. the % questions will come out on user, which is fair enough, since the % prompt is just a single space and isn't all that obvious. $repply([], []) :- !, nl, write(yes), nl. $repply([], _) :- !, $repply, nl, write(yes), nl. $repply([Name=Variable|Variables], _) :- nl, write(Name), write(' = '), write(Variable), !, $repply(Variables, yes). % consult and reconsult consult(File):- $break($csult(0, File)). reconsult(File) :- $break($csult(1, File)). [File|Files] :- $conlist([File|Files]). $conlist([]) :- !. $conlist([File|Files]) :- !, $conlist(File), $conlist(Files). $conlist(-File) :- !, reconsult(File). $conlist(File) :- consult(File). $csult(Flag, File) :- Heap0 is heapused, Time0 is cputime, $recons(Flag), $checkfile(File), $read_file(File, consult), is(Time, -, cputime, Time0), is(Heap, -, heapused, Heap0), telling(Old, user), write(File), $csult(Flag), write(Heap), write(' bytes '), write(Time), write(' sec.'), nl, tell(Old), fail. $csult(_, _) :- $exit_break. $csult(0) :- !, write(' consulted '). $csult(1) :- !, write(' reconsulted '). $read_file(File, Status) :- seeing(Input, File), telling(Output), $cycle(Status), seen, see(Input), tell(Output), fail. $read_file(_, _). $checkfile(File) :- atom(File), exists(File), !. $checkfile(File) :- atom(File), !, $error('Can''t read file', File). $checkfile(File) :- $error('File name is not an atom', File). % break break :- $break($break). $break :- $break_start, $read_file(user, question), $break_end, !, $exit_break. $break :- $exit_break. % just to make sure all_float(X, Y) :- $all_float(X0, X0), $flag_code(X0, X), nonvar(Y), $flag_code(Y0,Y), $all_float(_,Y0). expanded_exprs(X, Y) :- $carith(X0, X0), $flag_code(X0, X), nonvar(Y), $flag_code(Y0,Y), $carith(_,Y0). $flag_code(1, on). $flag_code(0,off). % expand_term(T0, T) % applies a sequence of transformations to T0 to produce T. % First the user's rules for term_expansion get a crack, then % the grammar-rule preprocessor has a go, and finally the % arithmetic expression "compiler" has a chance. expand_term(T0, T) :- $user_call(term_expansion(T0, T1)), !, $expand_term(T1, T). % Bypass grammar rules expand_term(T0, T) :- $translate_rule(T0, T1), !, $expand_term(T1, T). expand_term(T0, T) :- $expand_term(T0, T). $expand_term((H :- B0), (H :- B)) :- $compile_arith(B0, B), !. $expand_term(T, T). end_of_file. % needed here for a special reason... lib 0 0 0 100400 1443 ` % File : pl/lib % Author : R.A.O'Keefe % Updated: 20 November 1983 % Purpose: provide the PDP-11 Prolog lib(X) command. /* The point of this command is to make it easy for people to load files from a common library area. It also lets you have multiple libraries. lib(File) reconsults a file, looking for it in each library until it is found. If it can't find the file in the library, it tries the file name as written. If you want it to try other places, add your own clauses to libdirectory(D) which is a user-extensible table of places for the lib command to look. If the argument D contains a ? sign, the file name will replace that ?. Otherwise a / and the file name will be appended. lib(File, FileFound) looks for the file like lib/1, but tells you what file it found, and leaves it to you to decide what to do with it. */ lib([File|Files]) :- !, lib(File), lib(Files). lib([]) :- !. lib(File) :- lib(File, FileFound), !, reconsult(FileFound). lib(File) :- reconsult(File). lib(File, FileFound) :- $lib(File, F), libdirectory(Directory), $lib(Directory, D), $lib(D, F, T), name(FileFound, T), exists(FileFound), !. $lib([C|S], [C|S]) :- integer(C), !. $lib(Atomic, String) :- name(Atomic, String). $lib([63|D], F, T) :- !, % 63 is "?" $append(F, D, T). $lib([C|D], F, [C|T]) :- $lib(D, F, T). $lib([], F, [58|F]). % 58 is ":" libdirectory(cplog). listing 0 0 0 100400 6777 ` /* File : $Prolog/pl/listing Authors: Lawrence Byrd + Richard O'Keefe Updated: 20 November 1983 Purpose: Assorted output routines defined in Prolog. The predicates defined are print/1, listing/0, and listing/1. New: portray_clause(Cl). The following magic numbers appear in put(N) calls: 32 = " ", 40 = "(", 41 = ")", 44 = ",", 91 = "[", 93 = "]", 124 = "|". The priority of ',' is assumed to be 1000, which is true in this Prolog. */ %----------------------------------------------------------------------------% % print(Term) % write a Term to the current output, calling the user's portray/1 % predicate at each step (except for tails of lists which have not % been matched in their entirety) to do any special formatting that % may be required, or reverting to 'write'-like behaviour if the % user doesn't want anything special done. Ideally, this should be % integrated into the debugging system, but alas it is not. % It is debatable whether the top level priority should be 1200, as % here, or 1000, as elsewhere and earlier. Input starts at 1200. % There are two special hacks for printing some sort of variable % names: $VAR(N) prints as , and $VAR(Atom) prints % as Atom without any quotes, even for upper case. print(Term) :- $print(Term, 1200). % Print a term taking surrounding operator priorities into account. $print(Term, Priority) :- ( var(Term) % _N style of variables | atomic(Term) % ordinary atoms & integers ), !, writeq(Term). % quotes around e.g. 'foo baz' $print('$VAR'(N), Priority) :- !, % ex-variables $print_var(N). $print(Term, Priority) :- % check for user-defined formatting $print(Term), !. $print({Term}, Priority) :- !, put(123), % 123 is "{" $print(Term, 1200), put(125). % 125 is "}" $print([Head|Tail], Priority) :- !, % list put(91), % 91 is "[" $print(Head, 1000), !, $print_tail(Tail). $print(Term, Priority) :- % prefix operator functor(Term, Functor, 1), $is_op(Functor, 0, Op, _, Rp), !, $put_ch(Op, Priority, 40), % 40 is "(" $put_op(Functor, 1, 0), $print_arg(Rp, Term, 1), $put_ch(Op, Priority, 41). % 41 is ")" $print(Term, Priority) :- % postfix operator functor(Term, Functor, 1), $is_op(Functor, 2, Op, Lp, _), !, $put_ch(Op, Priority, 40), % 40 is "(" $print_arg(Lp, Term, 1), $put_op(Functor, 0, 1), $put_ch(Op, Priority, 41). % 41 is ")". $print(Term, Priority) :- % infix operator functor(Term, Functor, 2), $is_op(Functor, 1, Op, Lp, Rp), !, $put_ch(Op, Priority, 40), % 40 is "(" $print_arg(Lp, Term, 1), $put_op(Functor, 0, 0), $print_arg(Rp, Term, 2), $put_ch(Op, Priority, 41). % 41 is ")" $print(Term, Priority) :- functor(Term, Functor, N), writeq(Functor), $print(0, N, Term). $print(Term) :- $print_arg(Term), !, fail. $print(Term). % print_var(X) handles $VAR(X). $print_var(N) :- integer(N), N >= 0, !, put("A"+N mod 26), ( N < 26 | M is N//26, write(N) ), !. $print_var(A) :- atom(A), !, write(A). $print_var(X) :- writeq('$VAR'(X)). $print_arg(Term) :- portray(Term), !, fail. $print_arg(Term). % $print_arg(Priority, Term, ArgNo) % print the Argnoth argument of Term with the given Priority. $print_arg(Priority, Term, ArgNo) :- arg(ArgNo, Term, Arg), $print(Arg, Priority). % $put_op(Op, LeftContext, RightContext) % display an operator symbol with spacing dependent on its left and % right contexts. This should be done at the putatomq level, which % doesn't exist in this version of Prolog. $put_op(',', _, _) :- !, write(', '). $put_op(';', _, _) :- !, write('; '). $put_op(Functor, L, R) :- $put_ch(1, L, 32), % 32 is " " write(Functor), $put_ch(1, R, 32). % 32 is " " % print the arguments of a term $print(0, N, Term) :- !, put(40), % 40 is "(" $print_arg(1000, Term, 1), !, $print(1, N, Term). $print(N, N, Term) :- !, put(41). % 41 is ")" $print(L, N, Term) :- succ(L, M), write(', '), $print_arg(1000, Term, M), !, $print(M, N, Term). % $put_ch(Priority, Context, Character) % print Character if the Priority exceeds that of its Context. $put_ch(Priority, Context, Character) :- Priority > Context, !, put(Character). $put_ch(_, _, _). % $print_tail(List) % Print the tail of a list, being careful not to instantiate a % possible variable at the (current) end of the list. $print_tail(List) :- nonvar(List), List = [Head|Tail], !, put(44), % 44 is "," $print(Head, 1000), !, $print_tail(Tail). $print_tail(Tail) :- Tail \== [], put(124), % 124 is "|" $print(Tail, 1000), !, $print_tail([]). $print_tail([]) :- put(93). % 93 is "]" %----------------------------------------------------------------------------% % listing % calls listing(Pred) for each current_predicate Pred. listing :- current_predicate(_,Pred), nl, $list_clauses(Pred). listing. % listing(PredSpecs) % Takes a predicate specifier F/N, a partial specifier F, or a % list of such things, and lists each current_predicate Pred % matching one of these specifications. listing(V) :- var(V), !. % ignore variables listing([]) :- !. listing([X|Rest]) :- !, listing(X), listing(Rest). listing(X) :- $functorspec(X,Name,Arity), current_predicate(Name,Pred), functor(Pred,Name,Arity), nl, $list_clauses(Pred). listing(_). $list_clauses(Pred) :- clause(Pred, Body), portray_clause((Pred:-Body)), fail. portray_clause((Pred:-Body)) :- numbervars(Pred+Body, 0, _), print(Pred), $list_clauses(Body, 0, 2, 8), !. portray_clause((Pred)) :- portray_clause((Pred:-true)). $list_clauses((A,B), L, R, D) :- !, $list_clauses(A, L, 1, D), !, $list_clauses(B, 1, R, D). $list_clauses(true, L, 2, D) :- !, put(46), nl. % 46 is "." $list_clauses((A;B), L, R, D) :- !, $list_magic(fail, L, D), $list_magic((A;B), 0, 2, D), $list_magic(R, '. '). $list_clauses((A->B), L, R, D) :- !, $list_clauses(A, L, 5, D), !, $list_clauses(B, 5, R, D). $list_clauses(Goal, L, R, D) :- $list_magic(Goal, L, D), print(Goal), $list_magic(R, '. '). $list_magic(!, 0, D) :- !, write(' :- '). $list_magic(!, 1, D) :- !, write(', '). $list_magic(Goal, 0, D) :- !, write(' :- '), nl, tab(D). $list_magic(Goal, 1, D) :- !, put(44), % 44 is "," nl, tab(D). $list_magic(Goal, 3, D) :- !, write('( '). $list_magic(Goal, 4, D) :- !, write('| '). $list_magic(Goal, 5, D) :- !, write(' ->'), nl, tab(D). $list_magic(2, C) :- !, write(C). $list_magic(_, _). $list_magic((A;B), L, R, D) :- !, $list_magic(A, L, 1, D), !, $list_magic(B, 1, R, D). $list_magic(Conj, L, R, D) :- plus(D, 8, E), plus(L, 3, M), $list_clauses(Conj, M, 1, E), nl, tab(D), $list_magic(R, ')'). ops 0 0 0 100400 1584 ` % File : pl/ops % Author : Richard A. O'Keefe % Updated: 8 October 1983 % Purpose: define current_op/3 and is_op/5. % current_op(Priority, Type, Operator) % succeeds when there is a current definition of Symbol as an operator % of type Type and priority Priority. It may be used to check a given % operator or to enumerate them (slowly). current_op(Priority, Type, Operator) :- var(Operator), !, current_atom(Operator), current_op(Priority, Type, Operator). current_op(Priority, Type, Operator) :- atom(Operator), $op(Type, Num), % map names to codes 0, 1, 2 $is_op(Operator, Num, Priority, Left, Right), $op(Type, Priority, Left, Right). $op( fx, 0). $op( fx, O, _, P) :- succ(P, O). $op( fy, 0). $op( fy, O, _, O). $op(xf, 2). $op(xf, O, P, _) :- succ(P, O). $op(yf, 2). $op(yf, O, O, _). $op(xfy, 1). $op(xfy, O, P, O) :- succ(P, O). $op(xfx, 1). $op(xfx, O, P, P) :- succ(P, O). $op(yfx, 1). $op(yfx, O, O, P) :- succ(P, O). % is_op(Operator, Fixity, Priority, Left, Right) % is true when Operator is currently defined as a prefix/infix/postfix % operator {Fixity = fx/xfx/xf} of priority Priority, whose left/right % arguments have priorities Left/Right (arbitrary if there is no such % argument). is_op(Operator, Type, Priority, Left, Right) :- var(Operator), !, current_atom(Operator), is_op(Operator, Type, Priority, Left, Right). is_op(Operator, Type, Priority, Left, Right) :- atom(Operator), $is_op(Type, Num), $is_op(Operator, Num, Priority, Left, Right). $is_op( fx, 0). $is_op(xfx, 1). $is_op(xf, 2). protect 0 0 0 100400 1735 ` /* protect : Setting the flags for the system predicates Fernando Pereira Updated: 17 September 83 */ $mem(X, [X|_]). $mem(X, [_|Rest]) :- $mem(X, Rest). $unprotected(term_expansion, 2). $unprotected(libdirectory, 1). % Predicate flags used here: % % % 128 (PROTECTED) % 64 (INVISIBLE) % 32 (UNTRACEABLE) % Cut must be transparent due to the way it is currently % implemented (this fixes bug that prevented tracing % past cuts). % Note that transparent also seem to imply untraceable, % which means you don't see cuts at all. :- $sysflgs(!, 64). % This list are all transparent and untraceable. :-(( $mem(Pred, [call(_), (_,_), (_;_), $call(_), $hidden_call(_)]), $sysflgs(Pred, 96), fail ; % ALL predicates whose names start with a dollar sign % are made untraceable. current_atom(Atom), name(Atom, [36|_]), $current_functor(Atom, Arity, 256, 0), functor(Pred, Atom, Arity), $flags(Pred, Flags, Flags\/32), fail ; % The following predicates are better off invisible so % they are made untraceable as well. $mem(Pred, [write(_), writeq(_), get0(_), skip(_), put(_), nl, tab(_), display(_), print(_), listing, listing(_)]), $sysflgs(Pred, 32), fail ; % And now - ALL current predicates but those specified % by $unprotected are turned into % system predicates (which cannot be redefined, seen % by listing etc). current_atom(Atom), $current_functor(Atom, Arity, 256, 0), \+ $unprotected(Atom, Arity), functor(Pred, Atom, Arity), $flags(Pred, Flags, Flags\/128), fail ; % Finally, stop treating $ as a lower-case letter. % Instead, treat it like a cross-hatch chtype("#", Symbol, Symbol), chtype("$", Letter, Symbol) )). samsort 0 0 0 100400 1116 ` samsort([], []) :- !. samsort(List, Sort) :- samsort(List, [], 0, Sort). samsort([], Stack, R, Ans) :- !, fuse(Stack, 0, [Ans]). samsort(List, Stack, R, Ans) :- run_up(List, Run, Rest), S is R+1, fuse([Run|Stack], S, NewStack), !, samsort(Rest, NewStack, S, Ans). run_up([Head,HdTl|Tail], [Head|More], Rest) :- Head =< HdTl, !, run_up([HdTl|Tail], More, Rest). run_up([Head|Tail], [Head], Tail). fuse([A,B|Rest], K, Ans) :- 0 is K mod 2, !, J is K / 2, merge(A, B, C), !, fuse([C|Rest], J, Ans). fuse(Stack, _, Stack). merge(A, [], A) :- !. merge([], B, B) :- !. merge([A|R], [B|S], [B|T]) :- A > B, !, merge([A|R], S, T). merge([A|R], B, [A|T]) :- merge(R, B, T). run([Head|Tail], Run, Rest) :- Queue = [Head|_], !, run(Tail, Queue, Queue, Run, Rest). run([Head|Tail], QH, QT, Run, Rest) :- !, run(QH, QT, Head, Tail, Run, Rest). run([], Run, [_], Run, []). run([Ah|At], Qt, H, T, Run, Rest) :- H < Ah, !, run(T, [H,Ah|At], Qt, Run, Rest). run(Qh, [Qt], H, T, Qh, [H|T]) :- H < Qt, !. run(Qh, [_|Qt], H, T, Run, Rest) :- Qt = [H|Nt], !, run(T, Qh, Qt, Run, Rest). setof 0 0 0 100400 3147 ` % File : pl/setof % Author : David Warren, Fernando Pereira, R.A.O'Keefe % Updated: 16 November 1983 % Purpose: define setof/3, bagof/3, findall/3, and findall/4 % Needs : pl/sort, and has to be in the base load. % 16Nov83: split into setof and sort. Top level of setof % : rewritten, introducing findall, and $bag bug fixed. % The "existential quantifier" symbol is only significant to bagof % and setof, which it stops binding the quantified variable. % op(200, xfy, ^) is defined in the bootstrap file. Variable^Goal :- call(Goal). % findall/3 is a simplified version of bagof which has an implicit % existential quantifier on every variable. findall(Template, Generator, Answers) :- recorda($, $, Ref), $findall(Template, Generator, Ref, [], Answers). findall(Template, Generator, SoFar, Answers) :- recorda($, $, Ref), $findall(Template, Generator, Ref, SoFar, Answers). $findall(Template, Generator, _, _, _) :- $user_call(Generator), recorda($, Template, _), fail. $findall(_, _, Ref, SoFar, Answers) :- $findall(Ref, SoFar, Answers). $findall(Ref, SoFar, Answers) :- recorded($, Term, Tref), !, erase(Tref), ( Tref == Ref, !, Answers = SoFar ; $findall(Ref, [Term|SoFar], Answers) ). setof(Template, Generator, Set) :- bagof(Template, Generator, Bag), sort(Bag, Set0), Set = Set0. bagof(Template, Generator, Bag) :- $excess_vars(Generator, Template, [], FreeVars), FreeVars \== [], !, Key =.. [$|FreeVars], recorda($, $, Ref), $findall(Key-Template, Generator, Ref, [], Bags0), keysort(Bags0, Bags), $pick(Bags, Key, Bag). bagof(Template, Generator, Bag) :- recorda($, $, Ref), $findall(Template, Generator, Ref, [], Bag0), Bag0 \== [], Bag = Bag0. $pick(Bags, Key, Bag) :- Bags \== [], $parade(Bags, Key1, Bag1, Bags1), $decide(Key1, Bag1, Bags1, Key, Bag). $parade([K-X|L1], K, [X|B], L) :- !, $parade(L1, K, B, L). $parade(L, K, [], L). $decide(Key, Bag, Bags, Key, Bag) :- ( Bags = [], ! ; true ). $decide(_, _, Bags, Key, Bag) :- $pick(Bags, Key, Bag). $excess_vars(T, X, L0, L) :- var(T), !, ( $no_occurrence(T, X), !, $introduce(T, L0, L) ; L = L0 ). $excess_vars(X^P, Y, L0, L) :- !, $excess_vars(P, (X,Y), L0, L). $excess_vars(setof(X,P,S), Y, L0, L) :- !, $excess_vars((P,S), (X,Y), L0, L). $excess_vars(bagof(X,P,S), Y, L0, L) :- !, $excess_vars((P,S), (X,Y), L0, L). $excess_vars(T, X, L0, L) :- functor(T, _, N), $rem_excess_vars(N, T, X, L0, L). $rem_excess_vars(0, _, _, L, L) :- !. $rem_excess_vars(N, T, X, L0, L) :- succ(M, N), arg(N, T, T1), $excess_vars(T1, X, L0, L1), $rem_excess_vars(M, T, X, L1, L). $introduce(X, L, L) :- $included(X, L), !. $introduce(X, L, [X|L]). $included(X, L) :- $doesnt_include(L, X), !, fail. $included(X, L). $doesnt_include([], X). $doesnt_include([Y|L], X) :- Y \== X, $doesnt_include(L, X). $no_occurrence(X, Term) :- $contains(Term, X), !, fail. $no_occurrence(X, Term). $contains(T, X) :- var(T), !, T == X. $contains(T, X) :- functor(T, _, N), $upto(N, I), arg(I, T, T1), $contains(T1, X). $upto(N, N). $upto(N, I) :- succ(M, N), $upto(M, I). sort 0 0 0 100400 3847 ` % File : pl/sort % Authors: David Warren, Fernando Pereira, R.A.O'Keefe % Updated: 20 November 1983 % Purpose: sorting routines. % Defines: keysort/2, length/2, merge/3, msort/2, sort/2. /* The three sorting routines are all variations of merge-sort, done by bisecting the list, sorting the nearly equal halves, and merging the results. The half-lists aren't actually constructed, the number of elements is counted instead (which is why 'length' is in this file). The Dec-10 version doesn't have msort built in (it can be found in a library file -- ordsets), but it is a very convenient thing to have. The Dec-10 version of this file had a lot of calls to $comprise, the point of that was that by using mode declarations the compiler could put more variables on the local stack instead of the global stack. I have removed these in favour of clarity. In the interests of space& time saving I have replaced some of the arithmetic by plus and succ. Those predicates are not available in Dec-10 Prolog, but are quite a saving in C-Prolog. Also in the interests of space saving, $compare has been given a 4th argument to say which component to compare. It will compare Kel=Val as happily as it will compare Key-Val. Most significantly, it makes a space saving of 12% in sort, a space saving of 18% in keysort, and a time saving of 10% in keysort. The time to sort 200 elements is sort: 7.1 sec, keysort: 6.2 sec, and my new msort: 5.0 sec. A rough figure is 4msec * N * lg(N). */ % length of a list. length([], 0) :- !. length([_|L], N) :- length(L, M), succ(M, N). % sort(Random, Ordered) % do a merge sort on Random, eliminating duplicates. sort(L, R) :- length(L, N), $sort(N, L, _, R1), R = R1. $sort(2, [X1,X2|L], L, R) :- !, compare(Delta, X1, X2), ( Delta = (<), !, R = [X1,X2] ; Delta = (>), !, R = [X2,X1] ; /*Delta = (=) */ R = [X2] ). $sort(1, [X|L], L, [X]) :- !. $sort(0, L, L, []) :- !. $sort(N, L1, L3, R) :- is(N1, //, N, 2), plus(N1, N2, N), $sort(N1, L1, L2, R1), $sort(N2, L2, L3, R2), $merge(R1, R2, R). $merge([], R, R) :- !. $merge(R, [], R) :- !. $merge(R1, R2, [X|R]) :- $compare(Delta, R1, R2, 1), ( Delta = (<), !, R1 = [X|R1a], $merge(R1a, R2, R) ; Delta = (>), !, R2 = [X|R2a], $merge(R1, R2a, R) ; /* = */ R1 = [X|R1a], R2 = [_|R2a], $merge(R1a, R2a, R) ). % msort(Random, Ordered) % sorts a random list and does not remove duplicates. msort(L, R) :- length(L, N), $msort(N, L, _, R1), R = R1. $msort(2, [X1,X2|L], L, R) :- !, compare(Delta, X1, X2), ( Delta = (>), !, R = [X2,X1] ; /*Delta/= (>)*/ R = [X1,X2] ). $msort(1, [X|L], L, [X]) :- !. $msort(0, L, L, []) :- !. $msort(N, L1, L3, R) :- is(N1, //, N, 2), plus(N1, N2, N), $msort(N1, L1, L2, R1), $msort(N2, L2, L3, R2), merge(R1, R2, R). merge([], R, R) :- !. merge(R, [], R) :- !. merge(R1, R2, [X|R]) :- $compare(Delta, R1, R2, 1), ( Delta = (>), R2 = [X|L], merge(R1, L, R) ; /* = or < */ R1 = [X|L], merge(L, R2, R) ). % keysort(Random, Ordered) % sorts a random list of Key-Value pairs, and does not remove duplicates. keysort(L, R) :- length(L, N), $keysort(N, L, _, R1), R = R1. $keysort(2, [X1,X2|L], L, R) :- !, $compare(Delta, X1, X2, 1), ( Delta = (>), !, R = [X2,X1] ; /*Delta/= (>)*/ R = [X1,X2] ). $keysort(1, [X|L], L, [X]) :- !. $keysort(0, L, L, []) :- !. $keysort(N, L1, L3, R) :- is(N1, //, N, 2), plus(N1, N2, N), $keysort(N1, L1, L2, R1), $keysort(N2, L2, L3, R2), $keymerge(R1, R2, R). $keymerge([], R, R) :- !. $keymerge(R, [], R) :- !. $keymerge(R1, R2, [X|R]) :- R1 = [X1|R1a], R2 = [X2|R2a], $compare(Delta, X1, X2, 1), ( Delta = (>), !, X = X2, $keymerge(R1, R2a, R) ; /*Delta\= (>)*/ X = X1, $keymerge(R1a, R2, R) ). tracing 0 0 0 100400 4121 ` /* File : pl/tracing Author : Lawrence Byrd? + Richard O'Keefe Updated: 17 September 83, 1983, 8:00:07 pm Purpose: interface to tracing flags Note: this file is NOT responsible for producing tracing output. That is in main.c, which must also agree with this file on which bits mean what. */ debug :- $debug(P, 1), ( P = 1, $message('Debug mode already ', on) | P = 0, $message('Debug mode switched ', on) ), !. nodebug :- $debug(P, 0), ( P = 0, $message('Debug mode already ', off) | P = 1, ( $someleft, $allspyremove, $message('All spy-points ', removed) | true ), $message('Debug mode switched ', off) ), !. spy(X) :- $spy(X, on), $someleft, debug, fail. spy(_). nospy(X) :- $spy(X, off), fail. nospy(_). leash(Old, New) :- $leash(X, X), $leashcode(X, Old), leash(New). leash(X) :- nonvar(X), $leashcode(X, N), $leash(P, N), !, telling(Old, user), $prleash(N), tell(Old), !. leash(X) :- $error('Invalid leash specification', leash(X)). $leashcode(full, 2'1111) :- !. $leashcode(on, 2'1111):- !. $leashcode(half, 2'1010) :- !. $leashcode(loose,2'1000) :- !. $leashcode(off, 2'0000) :- !. $leashcode(N, N) :- integer(N), N >= 0, N =< 2'1111, !. $prleash(N) :- $leashcode(Code, N), write('Leashing set to '), write(Code), !, $prleash([call,exit,back,fail], 8, N, no). $prleash([_|Codes], Mask, Bits, Seen) :- 0 is Mask /\ Bits, Next is Mask >> 1, !, $prleash(Codes, Next, Bits, Seen). $prleash([Code|Codes], Mask, Bits, Seen) :- Next is Mask >> 1, $prleash(Seen, ', ', ' ('), write(Code), !, $prleash(Codes, Next, Bits, yes). $prleash([], _, _, Seen) :- $prleash(Seen, ').', '.'), nl. $prleash(yes, Yes, _) :- !, write(Yes). $prleash(no, _, No) :- !, write(No). debugging :- $debug(D, D), ( D = 0, !, $message('Debug mode is ', off) | D = 1, !, $message('Debug mode is ', on), ( $someleft, !, telling(Old, user), write('Spy-points set on : '), nl, ( current_atom(Functor), $current_functor(Functor,Arity,2'100010000,2'11110000), tab(8), write(Functor/Arity), nl, fail | tell(Old) ) | $message('There are no spy-points ', set) ), $leash(L, L), $prleash(L) ), !. $spy(V, _) :- var(V), !, $error('Invalid procedure specification', spy(X)). $spy([], _) :- !. $spy([Head|Tail], Flag):- !, $spy(Head, Flag), $spy(Tail, Flag). $spy(X, off) :- $functorspec(X,Functor,Arity), ( var(Arity) | A = Arity ), ( $current_functor(Functor,A,2'100010000,2'11110000), !, ( $current_functor(Functor,Arity,2'100010000,2'11110000), functor(T,Functor,Arity), $flags(T,P,P/\2'11101111), $message('Removed spy-point on ', Functor/Arity), fail | true ) | $message('There is no spy-point on ', X) ), !. $spy(X,on) :- $functorspec(X,Functor,Arity), ( atom(X), ( $current_functor(Functor,Arity,2'100000000,2'11110000), functor(Head,Functor,Arity), $enter(Head,Functor,Arity), fail | $current_functor(Functor,_,2'100000000,2'11100000) | $message('You have no clauses for ', X) ) | functor(Head,Functor,Arity), ( $current_functor(Functor,Arity,256,2'111100000) | $message('You have no clauses for ', Functor/Arity) ), $enter(Head,Functor,Arity) ), !. $spy(_,_). $enter(Head,Functor,Arity) :- ( $current_functor(Functor,Arity,2'100010000,2'11110000), Message = 'There already is a spy-point on ' | $flags(Head,P,P), ( P/\2'11100000 =:= 0, $flags(Head,P,P\/2'10000) | true ), Message = 'Spy-point placed on ' ), !, $message(Message, Functor/Arity). $someleft :- current_atom(A), $current_functor(A,_,2'10000,2'10000), !. $allspyremove :- current_atom(F), $current_functor(F,A,2'100010000,2'11110000), functor(T,F,A), $flags(T,P,P/\2'11101111), fail. $allspyremove. $functorspec(V,_,_) :- var(V), !, $error('Invalid procedure specification', functor(V)). $functorspec(X,X,_) :- atom(X), !. $functorspec(F/N,F,N) :- atom(F), integer(N), !. $functorspec(X,_,_) :- $error('Invalid procedure specification', functor(X)). tty 0 0 0 100400 1247 ` /* File : pl/tty Author : R.A.O'Keefe Updated: 17 September 83, 1983 Purpose: define the tty* predicates for Dec-10 compatability NB: display does NOT switch to the terminal! A particularly nasty thing to watch out for here is that we can't afford to fail between the time we switch to 'user' and the time we switch back. Hence the 'is's. I had put these predicates in Prolog before Fernando put them into his C version. I have left them in Prolog because they are almost never used. Any time they are used, the dominant cost is likely to be I/O. ttyflush used to be here. It is now in C so that people can send control sequences to /dev/tty without fear of line folding, but can then force the buffered output out. As a hack, ttyflush(X) is equivalent to fflush(X) in C for any output file X. */ ttytab(Spaces) :- N is Spaces, telling(Old, user), tab(N), tell(Old). ttyput(Char) :- C is Char, telling(Old, user), put(C), tell(Old). ttynl :- telling(Old, user), nl, tell(Old). ttyget0(Char) :- seeing(Old, user), get0(C), see(Old), Char = C. ttyget(Char) :- seeing(Old, user), get(C), see(Old), Char = C. ttyskip(Char) :- C is Char, seeing(Old, user), skip(C), see(Old). unify 0 0 0 100400 1837 ` /* File: Unify.Pl Author: R.A.O'Keefe Updated: 17 September 83 This file exports two predicates: unify(X, Y) occurs_check(X, Y). unify(X, Y) is true when the two Prolog terms X and Y can be unified, using genuine unification with the occurs check, and is guaranteed to do the same bindings as X = Y when it succeeds. If you are doing theorem proving or type checking with Prolog, what you need is genuine unification, not Prolog's pattern match. As it might be useful, occurs_check(X, Y) fails when X occurs in Y. It only works when X is a Prolog variable, but does not check. The mode declarations for these predicate may seem surprising. A quirk(?) of the mode system is that mode + does permit variables to be passed in, provided they are not matched in any clause head. No other utilities are needed. Adapted to VAX on Wednesday March 16th, 1983, 11:22:59 pm :- public occurs_check/2, % var x term -> unify/2. % term x term -> :- mode occurs_check(+,+), % first arg is a variable occurs_check(+,+,+), unify(+,+), unify(+,+,+). */ unify(X, Y) :- var(X), var(Y), !, X = Y. % want unify(X,X) which fails occurs_check unify(X, Y) :- var(X), !, occurs_check(X, Y), X = Y. unify(X, Y) :- var(Y), !, occurs_check(Y, X), X = Y. unify(X, Y) :- atomic(X), !, X = Y. unify(X, Y) :- functor(X, F, N), functor(Y, F, N), unify(N, X, Y). unify(0, X, Y) :- !. unify(N, X, Y) :- succ(M, N), arg(N, X, Xn), arg(N, Y, Yn), unify(Xn, Yn), !, unify(M, X, Y). occurs_check(X, Y) :- var(Y), !, X \== Y. occurs_check(X, Y) :- atomic(Y), !. occurs_check(X, Y) :- functor(Y, _, N), occurs_check(N, X, Y). occurs_check(0, _, _) :- !. occurs_check(N, X, Y) :- succ(M, N), arg(N, Y, Yn), occurs_check(X, Yn), !, occurs_check(M, X, Y). visible 0 0 0 100400 1063 ` /* VISIBLE : Make normally hidden system predicates visible again Lawrence Updated: 16 January 82 */ % ALL predicates whose names start with a dollar sign % are made untracable (original state). invisible :- ( current_atom(A), name(A,[36|_]), $current_functor(A,Arity,256,0), functor(Pred,A,Arity), $flags(Pred,Flags,Flags\/32), fail ; true ). % ALL predicates whose names start with a dollar sign % are made tracable again. visible :- ( current_atom(A), name(A,[36|_]), $current_functor(A,Arity,256,0), functor(Pred,A,Arity), $flags(Pred,Flags,Flags/\2'10011111), fail ; true ). % Unlock all the system predicates unlock :- ( current_atom(A), $current_functor(A,Arity,128,128), functor(Pred,A,Arity), $flags(Pred,Flags,Flags/\2'01111111), asserta(unlocked_system_predicate(Pred)), fail ; true ). % Lock the system predicates back up again lock :- ( retract(unlocked_system_predicate(Pred)), $flags(Pred,Flags,Flags\/128), fail ; true ).