Mercurial > hg > plml
comparison prolog/utils.pl @ 0:0dd31a8c66bd
Initial check in to Mercurial, V.1
author | samer |
---|---|
date | Fri, 13 Jan 2012 15:29:02 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:0dd31a8c66bd |
---|---|
1 % Some general utilities | |
2 | |
3 :- module(utils,[ | |
4 | |
5 % type testing and enumeration | |
6 natural/1 % test or enumerate natural numbers | |
7 , isfinite/1 % check number is non NaN or Inf | |
8 , int/1 % test or enumerate integers | |
9 , in/2 | |
10 | |
11 % mathematical utilities | |
12 , max/3 | |
13 , min/3 | |
14 | |
15 % list utilities | |
16 , list_idx1_member/3 % like nth1 but more useful argument order | |
17 , apply_to_nth1/4 | |
18 , measure/3 % match list lengths | |
19 , equal_length/2 % match 2 list lengths | |
20 , getopts/2 | |
21 , rep/3 % make a list of repeats of the same term | |
22 , cons/3 % list constructror | |
23 , decons/3 % list deconstructor | |
24 | |
25 % comma lists | |
26 , cl_list/2 | |
27 , cl_list_vt/2 | |
28 , cl_length/2 | |
29 , cl_length_vt/2 | |
30 , cl_member/2 | |
31 | |
32 | |
33 % term manipulation | |
34 , copy_head/2 % check terms for same head and arity | |
35 , unify_args/5 | |
36 , reinstatevars/3 | |
37 , reinstatevars/4 | |
38 | |
39 % formatting and parsing | |
40 , aphrase/2 % like phrase but makes an atom instead of a string | |
41 , aphrase/3 % like aphrase but takes code list | |
42 , print_list/1 % writes each element on a new line | |
43 , printq_list/1 % as print_list but quotes atom as necessary | |
44 , print_numbered_list/1 | |
45 | |
46 % database management | |
47 , extensible/1 % declare dynamic multifile predicate | |
48 , bt_assert/1 | |
49 , bt_retract/1 | |
50 , strict_assert/1 | |
51 , strict_retract/1 | |
52 , browse/2 % browse predicate with unknown arity | |
53 , current_state/2 | |
54 , set_state/2 | |
55 | |
56 % file system utilities | |
57 , dir/2 % directory listing | |
58 , path_atom/2 % expand paths | |
59 , expand_path/2 % expand paths | |
60 | |
61 % operating system | |
62 , open_with/2 % apply shell command to a file (SIDE EFFECTS) | |
63 , open_with/3 % apply shell command to a file with options (SIDE EFFECTS) | |
64 , shellcmd/2 % apply shell command to arguments | |
65 , open_/1 % open with 'open' command (Mac OS X). | |
66 , fmt_shellcmd/3 % format a shell command with switches and args | |
67 , hostname/1 | |
68 | |
69 % user interaction | |
70 , read_char_echo/1 % read one character and echo it immediately | |
71 , get_key/2 % read and validate keypress | |
72 , userchk/1 % unary predicate which allows user to force failure | |
73 , prompt_for_key/3 | |
74 | |
75 % ---- high order stuff ---- | |
76 | |
77 % modes of computation | |
78 , retry/1 % keep trying until success | |
79 , parallel/1 % parallel computation using threads | |
80 , bt_call/2 % Construct backtrackable operation | |
81 , on_backtracking/1 | |
82 | |
83 % iteration | |
84 , exhaust/1 % trigger all solutions to a goal (SIDE EFFECTS) | |
85 , iterate/3 % apply predicate recursively till failure | |
86 | |
87 % mapping | |
88 , for_naturals/2 % call predicate with natural numbers N down to 1 | |
89 , mapints/2 % call predicate with integers | |
90 , mapints/3 | |
91 , mapargs/2, mapargs/3, mapargs/4 | |
92 , mapargs_x/4, mapargs_x/5, mapargs_x/6 | |
93 , mapargs_xx/6 | |
94 , sfold/4 % structural fold for lists | |
95 , take/3 | |
96 , drop/3 | |
97 , drop_while/3 | |
98 , take_while/3 | |
99 | |
100 % lambda expressions | |
101 , mcall/2, mcall/3, mcall/4 | |
102 | |
103 ]). | |
104 | |
105 /** <module> General utilities | |
106 | |
107 The predicates in this module can be divided into several groups as listed | |
108 below. | |
109 | |
110 ---+++ Type testing and enumeration | |
111 * natural/1 - test or enumerate natural numbers | |
112 * isfinite/1 - check number is non NaN or Inf | |
113 * int/1 - test or enumerate integers | |
114 * in/2 | |
115 | |
116 ---+++ mathematical utilities | |
117 * max/3 | |
118 * min/3 | |
119 | |
120 ---+++ list utilities | |
121 * list_idx1_member/3 % like nth1 but more useful argument order | |
122 * measure/3 - match list lengths | |
123 * equal_length/2 - match two list lenghts | |
124 * getopts/2 | |
125 * rep/3 - make a list of repeats of the same term | |
126 * cons/3 - make list from head and tail | |
127 * decons/3 - get head and tail from list | |
128 | |
129 ---+++ term manipulation | |
130 * copy_head/2 - check terms for same head and arity | |
131 * unify_args/5 | |
132 * reinstatevars/3 | |
133 * reinstatevars/4 | |
134 | |
135 ---+++ formatting and parsing | |
136 * aphrase/2 - like phrase but makes an atom instead of a string | |
137 * aphrase/3 - like aphrase but takes code list | |
138 * print_list/1 - write/1 each element, one per line | |
139 * printq_list/1 - as print_list but quotes atom as with writeq/1 | |
140 * print_numbered_list/1 - as print_list/1 but with line numbers | |
141 | |
142 ---+++ database management | |
143 * extensible/1 - declare dynamic multifile predicate | |
144 * bt_assert/1 | |
145 * bt_retract/1 | |
146 * strict_assert/1 | |
147 * strict_retract/1 | |
148 * browse/2 - browse predicate with unknown arity | |
149 * current_state/2 | |
150 * set_state/2 | |
151 | |
152 ---+++ file system utilities | |
153 * dir/2 - directory listing | |
154 * path_atom/2 - expand paths | |
155 * expand_path/2 - expand paths | |
156 | |
157 ---+++ operating system | |
158 * open_with/2 - apply shell command to a file (SIDE EFFECTS) | |
159 * open_with/3 - apply shell command to a file with options (SIDE EFFECTS) | |
160 * shellcmd/2 - apply shell command to arguments | |
161 * open_/1 - open with 'open' command (Mac OS X). | |
162 * fmt_shellcmd/3 - format a shell command with switches and args | |
163 * hostname/1 | |
164 | |
165 ---+++ user interaction | |
166 * read_char_echo/1 - read one character and echo it immediately | |
167 * get_key/2 - read and validate keypress | |
168 * userchk/1 - unary predicate which allows user to force failure | |
169 * prompt_for_key/3 - print message and get keypress from user | |
170 | |
171 ---+++ High order stuff | |
172 | |
173 ---++++ modes of computation | |
174 * retry/1 - keep trying until success | |
175 * parallel/1 - parallel computation using threads | |
176 * bt_call/2 - Construct backtrackable operation | |
177 , on_backtracking/1 | |
178 | |
179 ---++++ iteration | |
180 * exhaust/1 - trigger all solutions to a goal (SIDE EFFECTS) | |
181 * iterate/3 - apply predicate recursively till failure | |
182 | |
183 ---++++ mapping | |
184 * for_naturals/2 - call predicate with natural numbers N down to 1 | |
185 * mapints/2 - call predicate with integers | |
186 * mapints/3 | |
187 * mapargs/2, mapargs/3, mapargs/4 | |
188 * mapargs_xx/6 | |
189 * sfold/4 - structural fold for lists | |
190 * take/3 | |
191 * drop/3 | |
192 * drop_while/3 | |
193 * take_while/3 | |
194 | |
195 ---++++ lambda expressions | |
196 * mcall/2, mcall/3, mcall/4 | |
197 */ | |
198 | |
199 :- use_module(library(ops)). | |
200 | |
201 :- meta_predicate | |
202 exhaust(0) | |
203 , retry(0) | |
204 , iterate(2,?,?) | |
205 , drop_while(1,?,?) | |
206 , take_while(1,?,?) | |
207 , apply_to_nth1(?,2,?,?) | |
208 , for_naturals(+,1) | |
209 , for_ints(+,+,1) | |
210 , mapints(1,?) | |
211 , mapints(2,?,?) | |
212 , mapargs(1,?) | |
213 , mapargs(2,?,?) | |
214 , mapargs(3,?,?,?) | |
215 , mapargs_x(+,+,1,?) | |
216 , mapargs_x(+,+,2,?,?) | |
217 , mapargs_x(+,+,3,?,?,?) | |
218 , mapargs_xx(2,?,?,?,?,?) | |
219 , on_backtracking(0) | |
220 , bt_call(0,0) | |
221 , bt_assert(:) | |
222 , bt_retract(:) | |
223 , strict_assert(:) | |
224 , strict_retract(:) | |
225 , extensible(:) | |
226 , aphrase(2,?) | |
227 , aphrase(2,?,?) | |
228 . | |
229 | |
230 :- multifile user:path/2. | |
231 :- multifile user:demo/1. | |
232 :- dynamic current_state/2. | |
233 | |
234 | |
235 %% extensible(+P) is det. | |
236 % declares 'extensible' predicates, ie ones that can have new clauses | |
237 % added in other files. Equivalent to dynamic(P), multifile(P). | |
238 extensible(P) :- dynamic(P), multifile(P). | |
239 | |
240 | |
241 %% natural(+N) is semidet. | |
242 %% natural(-N:natural) is multi. | |
243 % | |
244 % Means N is a natural number (includes 0). If N is | |
245 % a variable, succeeds an infinite number of times on backtracking, | |
246 % returning all natural numbers. | |
247 natural(N) :- (var(N) -> between(0,inf,N); integer(N), N>=0). | |
248 | |
249 | |
250 %% int(+N) is semidet. | |
251 %% int(-N:integer) is multi. | |
252 % | |
253 % Means N is an integer. If N is | |
254 % a variable, succeeds an infinite number of times on backtracking, | |
255 % returning all integers starting at zero and interleaving positive | |
256 % and negative values. | |
257 int(N) :- nonvar(N), integer(N). | |
258 int(N) :- var(N), (N=0; (between(1,inf,M), (N=M; N is -M))). | |
259 | |
260 | |
261 %% isfinite(+N:number) is semidet. | |
262 % | |
263 % Succeeds when N is a finite number. | |
264 isfinite(N):- catch(_ is N+0,error(_,_),fail). % !! workable hack | |
265 | |
266 | |
267 %% in(+X,Set) is semidet. | |
268 %% in(-X,Set) is nondet. | |
269 % | |
270 % Simple testing and enumration of values in some sets. | |
271 % Set can be | |
272 % * {A,B,_} | |
273 % Explicit list of values. | |
274 % * natural | |
275 % Natural numbers starting from 0. | |
276 % * integer | |
277 % Natural numbers. | |
278 % * real | |
279 % Real (floating point) numbers. | |
280 % * A..B | |
281 % Integer range from A to B inclusive. | |
282 % * A--B | |
283 % Closed interval [A,B]. | |
284 X in A--\B :- X in A--(\B). | |
285 X in \A--(\B):- !, ch(A<X), ch(X<B). | |
286 X in \A--B :- !, ch(A<X), ch(X=<B). | |
287 X in A--(\B) :- !, ch(A=<X), ch(X<B). | |
288 X in A--B :- !, ch(A=<X), ch(X=<B). | |
289 X in A..B :- integer(A), integer(B), between(A,B,X). | |
290 X in {CList} :- member_clist(X,CList). | |
291 X in natural :- natural(X). % enumerate! | |
292 X in integer :- int(X). % enumerates! | |
293 X in real :- number(X). % same as X :: real | |
294 | |
295 | |
296 ch(_ =<inf) :- !. | |
297 ch(inf=< _ ) :- !, fail. | |
298 ch(-inf=< _) :- !. | |
299 ch(_ =<(-inf)) :- !, fail. | |
300 ch(A=<B) :- !, A=<B. | |
301 | |
302 ch(inf<_ ) :- !, fail. | |
303 ch(_ <inf) :- !. | |
304 ch(_ <(-inf)) :- !, fail. | |
305 ch(-inf<_ ) :- !. | |
306 ch(A<B) :- !, A<B. | |
307 | |
308 | |
309 | |
310 %% exhaust(:Goal) is det. | |
311 % | |
312 % Repeat Goal until failure, then succeed. | |
313 exhaust(Q) :- call(Q), fail; true. | |
314 | |
315 %% iterate(+P:pred(A,A), X:A, Y:A) is semidet. | |
316 % apply P recursively to X until failure, then return final value Y. | |
317 iterate(P,X,Y) :- call(P,X,Z) -> iterate(P,Z,Y); Y=X. | |
318 | |
319 %% sfold(Functor,Initial,L:list,Final) is semidet. | |
320 % *Structural* fold applied to a term, | |
321 % rather than a relational fold using a predicate name. | |
322 sfold(_,E,[],E). | |
323 sfold(O,E,[X|XX],R) :- R=..[O,X,YY], sfold(O,E,XX,YY). | |
324 | |
325 | |
326 %% dir( +Pattern, -File) is nondet. | |
327 % | |
328 % Directory listing for directory matching Pattern. File | |
329 % names are returned one by one on backtracking. | |
330 dir(Pattern,File) :- | |
331 expand_file_name(Pattern,List), | |
332 member(File,List). | |
333 | |
334 | |
335 %% path_atom( +Spec:path_expr, -Path:atom) is nondet. | |
336 % | |
337 % Expand a 'path expression' into a flat path (an atom). | |
338 % A path expression is defined by: | |
339 % == | |
340 % path_expr ---> atom % literal path component name | |
341 % ; path_expr/atom % child of path_expr | |
342 % ; path_macro % a previously defined abbr for a path. | |
343 % == | |
344 % A path_macro is defined using path/2. | |
345 | |
346 path_atom(P,C) :- path(P,C), atom(C). | |
347 | |
348 path_atom(PA/B,C) :- | |
349 once((nonvar(C); nonvar(B); nonvar(PA))), | |
350 path_atom(PA,A), | |
351 concat3atoms(A,'/',B,C). | |
352 | |
353 | |
354 path_atom(Path,Atom) :- path(Path, Def), \+atom(Def), path_atom(Def,Atom). | |
355 path_atom(Path,Atom) :- | |
356 nonvar(Path), | |
357 \+path(Path,_), | |
358 Path\=_/_, | |
359 Atom=Path. | |
360 | |
361 concat3atoms(A,B,C,ABC) :- | |
362 nonvar(A), nonvar(B), nonvar(C), !, concat_atom([A,B,C],ABC). | |
363 | |
364 concat3atoms(_,_,_,ABC) :- var(ABC), !, fail. | |
365 concat3atoms(A,B,C,ABC) :- nonvar(C), !, atom_concat(AB,C,ABC), atom_concat(A,B,AB). | |
366 concat3atoms(A,B,C,ABC) :- nonvar(A), !, atom_concat(A,BC,ABC), atom_concat(B,C,BC). | |
367 concat3atoms(A,B,C,ABC) :- | |
368 maplist(atom_codes,[B,ABC],[BX,ABCX]), | |
369 append(ABX,CX,ABCX), | |
370 append(AX,BX,ABX), | |
371 maplist(atom_codes,[A,C],[AX,CX]). | |
372 | |
373 %% expand_path( +P:path_expr, -FP:atom) is semidet. | |
374 % | |
375 % Expand path_exp including wildcards to fully qualified path | |
376 expand_path(P,FP) :- path_atom(P,PP), expand_file_name(PP,[FP]). | |
377 | |
378 | |
379 %% open_with( +Program:atom, +Thing:path_expr, +Options:list) is semidet. | |
380 %% open_with( +Program:atom, +Thing:path_expr) is semidet. | |
381 % | |
382 % The only option is bg, which adds "&" to make command execute in background. | |
383 open_with(Q,P) :- open_with(Q,P,[]). | |
384 open_with(Q,P,Opts) :- | |
385 expand_path(P,FP), | |
386 (member(bg,Opts) -> OO=' &'; OO=''), | |
387 sformat(S,'~w ~q~w',[Q,FP,OO]), | |
388 shell(S). | |
389 | |
390 %% open_( +Thing:path_expr) is semidet. | |
391 % Equivalent to open_with(open,Thing). | |
392 open_(P) :- open_with(open,P). | |
393 | |
394 %% shellcmd( +Head:atom, +Args:list(atom)) is det. | |
395 % | |
396 % Execute a shell command on a given list of arguments | |
397 shellcmd(Head,Args) :- | |
398 concat_atom([Head|Args],' ',Cmd), | |
399 shell(Cmd,_Status). | |
400 | |
401 %% fmt_shellcmd( +Prog:atom, +Args:list(shellarg), -Cmd) is det. | |
402 % make a shell command string. | |
403 fmt_shellcmd(Prog,Args,Cmd) :- | |
404 phrase(utils:shellcmd(l_(Args)),FArgs), | |
405 concat_atom([Prog|FArgs],' ',Cmd). | |
406 | |
407 shellcmd(l_([])) --> !, []. | |
408 shellcmd(l_([H|T])) --> !, shellcmd(H), shellcmd(l_(T)). | |
409 shellcmd(s(N,V)) --> !, shellcmd(s(N)), shellcmd(V). | |
410 shellcmd(q(X)) --> !, { concat_atom(['"',X,'"'],A) }, [A]. | |
411 shellcmd(s(N)) --> !, { | |
412 (atom_codes(N,[_]) -> F='-' ; F='--'), | |
413 atom_concat(F,N,A) }, [A]. | |
414 shellcmd(l(X)) --> [X]. | |
415 | |
416 | |
417 | |
418 %% read_char_echo( -C:atom) is det. | |
419 % | |
420 % Read a single character from the current input, | |
421 % echo it to the output. | |
422 read_char_echo(C) :- | |
423 get_single_char(Code), | |
424 put_code(Code), flush_output, | |
425 char_code(C,Code). | |
426 | |
427 | |
428 | |
429 %% set_state( +Key, +Value) is det. | |
430 % | |
431 % Maintains a mutable global set of Key-Value pairs, sets the value | |
432 % associated with Key to Value. | |
433 set_state(Flag,Value) :- | |
434 ground(Flag), | |
435 retractall(current_state(Flag,_)), | |
436 assert(current_state(Flag,Value)). | |
437 | |
438 | |
439 %% current_state( -Key, -Value) is nondet. | |
440 %% current_state( +Key, -Value) is semidet. | |
441 % | |
442 % Lookup the value associated with Key, or enumerate all the | |
443 % key value pairs. | |
444 | |
445 | |
446 | |
447 %% parallel( +List:list(query)) is semidet. | |
448 % | |
449 % Use this by giving a list of queries of the form | |
450 % [Vars2:Goal, Vars2:Goal2, ...] | |
451 % where Vars is the term that each thread must return | |
452 % when it has finished computing its Goal. The | |
453 % parallel predicate finishes when all the threads | |
454 % have finished, and should result in all the Vars | |
455 % being bound appropriately. | |
456 | |
457 parallel(Queries) :- | |
458 maplist(async,Queries,Collecters), | |
459 maplist(call,Collecters). | |
460 | |
461 % these are used to initiate and wait for each | |
462 % computation thread. | |
463 async_collect(Id,X:_) :- thread_join(Id,exited(X)). | |
464 async(X:Goal,utils:async_collect(Id,X:_)) :- | |
465 thread_create((Goal,thread_exit(X)),Id,[]). | |
466 | |
467 %% browse( +PredSpec, -Goal) is nondet. | |
468 % | |
469 % PredSpec is a term like (PredicateName/Arity). Goal | |
470 % is unified with solutions of PredicateName/Arity. | |
471 browse(P/A,Goal) :- | |
472 current_predicate(P/A), | |
473 length(L,A), | |
474 Goal=..[P|L], | |
475 call(Goal). | |
476 | |
477 | |
478 | |
479 %% aphrase(P:phrase(code), -A:atom, +S:list(code)) is nondet. | |
480 %% aphrase(P:phrase(code), +A:atom, -S:list(code)) is nondet. | |
481 %% aphrase(P:phrase(code), -A:atom, -S:list(code)) is nondet. | |
482 %% aphrase(P:phrase(code), -A:atom) is nondet. | |
483 % | |
484 % Generate or parse an atom using given DCG phrase P. | |
485 % aphrase(P,A) is equivalent to aphrase(P,A,_). | |
486 aphrase(X,A) :- aphrase(X,A,_). | |
487 aphrase(X,A,S) :- | |
488 ( ground(A) | |
489 -> atom_codes(A,S), phrase(X,S) | |
490 ; phrase(X,S), atom_codes(A,S)). | |
491 | |
492 | |
493 %% print_list( +L:list) is det. | |
494 % | |
495 % Print a list, one item per line. | |
496 print_list([]) :- writeln('~'), nl. | |
497 print_list([H|T]) :- print(H), nl, print_list(T). | |
498 | |
499 %% printq_list( +L:list) is det. | |
500 % | |
501 % Print a list, one item per line, as with writeq/1. | |
502 printq_list([]) :- writeln('~'), nl. | |
503 printq_list([H|T]) :- writeq(H), nl, printq_list(T). | |
504 | |
505 %% print_numbered_list( +L:list) is det. | |
506 % | |
507 % Print a list with numbered lines. | |
508 print_numbered_list(L) :- | |
509 length(L,Max), | |
510 number_codes(Max,MC), | |
511 length(MC,Width), | |
512 print_num_list(Width,1,L). | |
513 | |
514 print_num_list(_,_,[]) :- nl. | |
515 print_num_list(Width,N,[H|T]) :- succ(N,M), | |
516 copy_term(H,H1), | |
517 numbervars(H1,0,_), | |
518 number_codes(N,NC), " "=[Pad], | |
519 padleft(Pad,Width,NC,PNC), | |
520 format('~s. ~q\n',[PNC,H1]), | |
521 print_num_list(Width,M,T). | |
522 | |
523 padleft(_,W,In,In) :- length(In,W). | |
524 padleft(P,W,In,[P|Out]) :- succ(V,W), padleft(P,V,In,Out). | |
525 | |
526 | |
527 | |
528 | |
529 %% get_key( +Valid:list(char), -C:char) is det. | |
530 % | |
531 % Get and validate a key press from the user. The character | |
532 % must be one of the ones listed in Valid, otherwise, an | |
533 % error message is printed and the user prompted again. | |
534 get_key(Valid,C) :- | |
535 read_char_echo(D), nl, | |
536 ( member(D,Valid) -> C=D | |
537 ; D='\n' -> get_key(Valid,C) % this improves interaction with acme | |
538 ; format('Unknown command "~q"; valid keys are ~q.\n', [D,Valid]), | |
539 write('Command? '), | |
540 get_key(Valid,C)). | |
541 | |
542 | |
543 %% userchk(T) is semidet. | |
544 % | |
545 % Write T and ask this user if it is ok. User presses y or n. | |
546 % userchk succeeds if if the keypress was y and fails if it was n. | |
547 userchk(T) :- prompt_for_key(T,[y,n],y). | |
548 | |
549 | |
550 %% prompt_for_key( +Msg:atom, +Keys:list(char), -Key:char) is semidet. | |
551 % | |
552 % Prompt user for a keypress. Prompt message is Msg, and valid keys are | |
553 % listed in Keys. | |
554 prompt_for_key(Msg,Keys,Key) :- format('~p ~q? ',[Msg,Keys]), get_key(Keys,Key). | |
555 | |
556 % ------------------- TERM MANIPULATION ------------------------------ | |
557 | |
558 | |
559 %% copy_head(+T1,-T2) is det. | |
560 %% copy_head(+T1,+T2) is semidet. | |
561 % | |
562 % true if T1 and T2 have the same head and arity | |
563 copy_head(T1,T2) :- functor(T1,N,A), functor(T2,N,A). | |
564 | |
565 | |
566 | |
567 %% reinstatevars( F:atom, V:list, Eh, What) is nondet. | |
568 %% reinstatevars( V:list, Eh, What) is nondet. | |
569 % | |
570 % Reverse of numbervars. Each '$VAR'(N) subterm of X is replaced | |
571 % with the Nth element of V, which can be uninstantiated on entry | |
572 % reinstatevars/4 uses an arbitrary functor F instead of $VAR. | |
573 | |
574 reinstatevars(V,'$VAR'(N),Y) :- !, nth0(N,V,Y). | |
575 reinstatevars(_,X,Y) :- atomic(X), !, Y=X. | |
576 reinstatevars(V,X,Y) :- mapargs(reinstatevars(V),X,Y). | |
577 | |
578 reinstatevars(F,V,T,Y) :- functor(T,F,1), !, arg(1,T,N), nth0(N,V,Y). | |
579 reinstatevars(_,_,X,Y) :- atomic(X), !, Y=X. | |
580 reinstatevars(F,V,X,Y) :- mapargs(reinstatevars(F,V),X,Y). | |
581 | |
582 | |
583 %% unify_args( Src, SrcIndex, Dest, DestIndex, Num) is det. | |
584 % | |
585 % this unifies N consecutive arguments of Src and Dest starting | |
586 % from SI and DI in each term respectively | |
587 unify_args(_,_,_,_,0). | |
588 unify_args(Src,SI,Dest,DI,N) :- | |
589 arg(SI,Src,X), arg(DI,Dest,X), !, | |
590 succ(SI,SI2), succ(DI,DI2), succ(N2,N), | |
591 unify_args(Src,SI2,Dest,DI2,N2). | |
592 | |
593 | |
594 % ---------------------- LIST UTILITIES ----------------------------- | |
595 | |
596 | |
597 %member_clist(_,Z) :- var(Z), !, fail. | |
598 member_clist(A,A) :- A\=(_,_). | |
599 member_clist(A,(A,_)). | |
600 member_clist(A,(_,B)) :- member_clist(A,B). | |
601 | |
602 | |
603 | |
604 %% measure(Ruler,In,Out) is det. | |
605 % true if Out is the same length as Ruler but matches In as far as possible | |
606 measure([],_I,[]). | |
607 measure([_|R],[],[_|O]) :- measure(R,[],O). | |
608 measure([_|R],[X|I],[X|O]) :- measure(R,I,O). | |
609 | |
610 %% equal_length( ?In, ?Out) is nondet. | |
611 % equal_length( +L1:list, -L2:list) is det. | |
612 % equal_length( -L1:list, +L2:list) is det. | |
613 % | |
614 % True if L1 and L2 are the same length. | |
615 equal_length([],[]). | |
616 equal_length([_|T1],[_|T2]) :- equal_length(T1,T2). | |
617 | |
618 %split_at(0,T,I-I,T). | |
619 %split_at(N,[H|T],[H|I1]-Z,T1) :- succ(M,N), split_at(M,T,I1-Z,T1). | |
620 | |
621 %split_at2(0,T,I-I,T). | |
622 %split_at2(N,[H|T],[H|I1]-Z,T1) :- split_at2(M,T,I1-Z,T1), succ(M,N). | |
623 | |
624 %% max(+X:number, +Y:number, -Z:number) is det. | |
625 % | |
626 % Unify Z with the larger of X and Y. Legal values are | |
627 % any numerical value or inf or -inf. | |
628 max(_,inf,inf) :- !. | |
629 max(inf,_,inf) :- !. | |
630 max(X,-inf,X) :- !. | |
631 max(-inf,X,X) :- !. | |
632 max(X,Y,Z) :- X<Y -> Z=Y; Z=X. | |
633 | |
634 %% max(+X:number, +Y:number, -Z:number) is det. | |
635 % | |
636 % Unify Z with the larger of X and Y. Legal values are | |
637 % any numerical value or inf or -inf. | |
638 min(_,-inf,-inf) :- !. | |
639 min(-inf,_,-inf) :- !. | |
640 min(X,inf,X) :- !. | |
641 min(inf,X,X) :- !. | |
642 min(X,Y,Z) :- X<Y -> Z=X; Z=Y. | |
643 | |
644 %% list_idx1_member( +L:list(A), +N:natural, ?X:A) is semidet. | |
645 %% list_idx1_member( ?L:list(A), ?N:natural, ?X:A) is nondet. | |
646 % | |
647 % Equivalent to nth1(N,L,X). | |
648 list_idx1_member(L,I,X) :- nth1(I,L,X). | |
649 | |
650 | |
651 %% getopts( +Opts:list(option), ?Spec:list(optspec)) is det. | |
652 % | |
653 % Get value from option list. | |
654 % == | |
655 % option(A) ---> term(A). | |
656 % optspec ---> option(A)/A. | |
657 % == | |
658 getopts(OptsIn,Spec) :- maplist(getopt(OptsIn),Spec). | |
659 getopt(OptsIn,Option/Default) :- option(Option,OptsIn,Default). | |
660 | |
661 %% cons( ?Head:A, ?Tail:list(A), ?List:list(A)) is det. | |
662 % | |
663 % List constructor. | |
664 cons(H,T,[H|T]). | |
665 | |
666 %% decons( ?Head:A, ?List:list(A), ?Tail:list(A)) is det. | |
667 % | |
668 % List deconstructor. | |
669 decons(H,[H|T],T). | |
670 | |
671 % ---------------------- MAPPING, HIGH ORDER STUFF --------------------- | |
672 | |
673 %% for_naturals(+N:natural, P:pred(natural)) is nondet. | |
674 % apply predicate to each natural number from 1 to N (backwards) | |
675 for_naturals(0,_). | |
676 for_naturals(N,P) :- succ(M,N), call(P,N), for_naturals(M,P). | |
677 | |
678 %% mapints( +P:pred(integer,A), +R:intrange, -X:list) is nondet. | |
679 %% mapints( +P:pred(integer), +R:intrange) is nondet. | |
680 % | |
681 % Mapping predicates over lists of integers. Range is like M..N. | |
682 % mapints/3 maps 2 argument predicate over implicit list of | |
683 % integers M..N and explicit list of values X. | |
684 mapints(_,M..N) :- N<M, !. | |
685 mapints(P,M..N) :- call(P,M), plus(M,1,L), mapints(P,L..N). | |
686 | |
687 mapints(_,M..N,[]) :- N<M, !. | |
688 mapints(P,M..N,[X|T]) :- call(P,M,X), plus(M,1,L), mapints(P,L..N,T). | |
689 | |
690 %% rep( +N:natural, ?X:A, -L:list(A)) is det. | |
691 %% rep( -N:natural, ?X:A, -L:list(A)) is multi. | |
692 % Make a list consisting of N repeats of the same term. If called | |
693 % with N unbount, creates progressively longer and longer lists | |
694 % on backtracking. | |
695 rep(0,_,[]). | |
696 rep(N,A,[A|X]) :- | |
697 ( nonvar(N) | |
698 -> succ(M,N), rep(M,A,X) | |
699 ; rep(M,A,X), succ(M,N) | |
700 ). | |
701 | |
702 %% mapargs( P:pred(A,B,C), T1:tuple(F,A), T2:tuple(F,B), T3:tuple(F,C)) is nondet. | |
703 %% mapargs( P:pred(A,B), T1:tuple(F,A), T2:tuple(F,B)) is nondet. | |
704 %% mapargs( P:pred(A), T1:term) is nondet. | |
705 % | |
706 % Map predicate over to args of a term preserving head. | |
707 % A tuple(F,A) is a term with head functor F and any number of arguments | |
708 % of type A, ie | |
709 % == | |
710 % tuple(F,A) ---> F ; F(A) ; F(A,A) ; F(A,A,A) ; .. . | |
711 % == | |
712 | |
713 mapargs(P,T1) :- | |
714 functor(T1,_,N), | |
715 mapargs_x(1,N,P,T1). | |
716 | |
717 mapargs(P,T1,T2) :- | |
718 ( nonvar(T1) | |
719 -> functor(T1,F,N), functor(T2,F,N) | |
720 ; functor(T2,F,N), functor(T1,F,N)), | |
721 mapargs_x(1,N,P,T1,T2). | |
722 | |
723 mapargs(P,T1,T2,T3) :- | |
724 functor(T1,F,N), | |
725 functor(T2,F,N), | |
726 functor(T3,F,N), | |
727 mapargs_x(1,N,P,T1,T2,T3). | |
728 | |
729 mapargs_x(I,N,P,T1) :- | |
730 ( I>N -> true | |
731 ; arg(I,T1,X1), | |
732 call(P,X1), | |
733 succ(I,J), mapargs_x(J,N,P,T1)). | |
734 | |
735 mapargs_x(I,N,P,T1,T2) :- | |
736 ( I>N -> true | |
737 ; arg(I,T1,X1), | |
738 arg(I,T2,X2), | |
739 call(P,X1,X2), | |
740 succ(I,J), mapargs_x(J,N,P,T1,T2)). | |
741 | |
742 mapargs_x(I,N,P,T1,T2,T3) :- | |
743 ( I>N -> true | |
744 ; arg(I,T1,X1), | |
745 arg(I,T2,X2), | |
746 arg(I,T3,X3), | |
747 call(P,X1,X2,X3), | |
748 succ(I,J), mapargs_x(J,N,P,T1,T2,T3)). | |
749 | |
750 %% drop( +N:natural, +In:list(A), -Out:list(A)) is det. | |
751 drop(0,T,T). | |
752 drop(N,[_|T],V) :- succ(M,N), drop(M,T,V). | |
753 | |
754 | |
755 %% take( +N:natural, +In:list(A), -Out:list(A)) is det. | |
756 take(N,T,X) :- length(X,N), append(X,_,T). | |
757 | |
758 | |
759 %% drop_while( +P:pred(A), +In:list(A), -Out:list(A)) is det. | |
760 % | |
761 % Remove all elements from head of In that are accepted by P | |
762 % and return the remained in Out. | |
763 drop_while(P,[X|T],V) :- call(P,X) -> drop_while(P,T,V); V=[X|T]. | |
764 | |
765 | |
766 %% take_while( +P:pred(A), +In:list(A), -Out:list(A)) is det. | |
767 % | |
768 % Remove all elements from head of In that are accepted by P | |
769 % and return them in Out. | |
770 take_while(P,[X|T],O) :- call(P,X) -> O=[X|V], take_while(P,T,V); O=[]. | |
771 | |
772 | |
773 | |
774 %% retry( :Goal) is det. | |
775 % | |
776 % Keep retrying Goal until it succeeds. Only makes sense if Goal | |
777 % has side effects. Might be nonterminating. | |
778 retry(G) :- once((repeat,G)). | |
779 | |
780 %% apply_to_nth1( N:natural, Op:pred(A,A), +In:list(A), +Out:list(A)) is nondet. | |
781 % | |
782 % Apply predicate Op to the N th element of list In and unify Out with the result. | |
783 %apply_to_nth1(N,Op,Old,Init) :- | |
784 % ( nonvar(N) | |
785 % -> succ(M,N), split_at(M,Old,Init-[Y|Tail],[X|Tail]) | |
786 % ; split_at2(M,Old,Init-[Y|Tail],[X|Tail]), succ(M,N) | |
787 % ), | |
788 % call(Op,X,Y). | |
789 | |
790 apply_to_nth1(1,P,[X|XX],[Y|XX]) :- call(P,X,Y). | |
791 apply_to_nth1(N,P,[X|X1],[X|Y1]) :- nonvar(N), !, N>1, succ(M,N), apply_to_nth1(M,P,X1,Y1). | |
792 apply_to_nth1(N,P,[X|X1],[X|Y1]) :- var(N), !, apply_to_nth1(M,P,X1,Y1), succ(M,N). | |
793 | |
794 | |
795 %% mapargs_xx( +P:pred(A,B), +Src:term(_,A), +SrcIndex:natural, +Dest:term(_,B), +DestIndex:natural, +N:natural) is nondet. | |
796 % | |
797 % Maps predicate P over N consecutive arguments of Src and Dest. Starts | |
798 % at SrcIndex th argument of Src and DestIndex th argument of Dest. | |
799 mapargs_xx(_,_,_,_,_,0). | |
800 mapargs_xx(Pred,Src,SI,Dest,DI,N) :- | |
801 arg(SI,Src,SX), arg(DI,Dest,DX), call(Pred,SX,DX), !, | |
802 succ(SI,SI2), succ(DI,DI2), succ(N2,N), | |
803 mapargs_xx(Pred,Src,SI2,Dest,DI2,N2). | |
804 | |
805 | |
806 %% mcall(P:pred(A), X:A) is nondet. | |
807 %% mcall(P:pred(A,B), X:A, Y:B) is nondet. | |
808 %% mcall(P:pred(A,B,C), X:A, Y:B, Z:C) is nondet. | |
809 %% mcall(P:pred(A,B,C,D), X:A, Y:B, Z:C, W:D) is nondet. | |
810 % | |
811 % Like call/N but P can additionally be a lambda expression in one of several | |
812 % forms: | |
813 % * Tuple :- Body | |
814 % If functor(Tuple,\,N), Body is executed after unifying tuple arguments | |
815 % with arguments to mcall, eg =mcall(\(X):-member(X,[a,b,c]),Y)= is equivalent | |
816 % to member(Y,[a,b,c]), or =mcall(\(X,Y):-nth1(X,[a,b,c],Y),2,c)=. | |
817 % * Tuple | |
818 % Equivalent to Tuple:-true. | |
819 | |
820 mcall(P,A) :- mc(P,\(A),Q), Q. | |
821 mcall(P,A,B) :- mc(P,\(A,B),Q), Q. | |
822 mcall(P,A,B,C) :- mc(P,\(A,B,C),Q), Q. | |
823 mcall(P,A,B,C,D) :- mc(P,\(A,B,C,D),Q), Q. | |
824 | |
825 mc(Tuple:-Body,Params,Goal) :- !, copy_term(Tuple/Body,Params/Goal). | |
826 mc(Tuple,Params,true) :- functor(Tuple,\,_), !, copy_term(Tuple,Params). | |
827 mc(P,Params,apply(P,Args)) :- Params=..[\|Args]. | |
828 | |
829 | |
830 %% on_backtracking( :Goal) is det. | |
831 % | |
832 % The first time this is called, it succeeds and does nothing. | |
833 % On backtracking, Goal is called and then a failure is generated. | |
834 | |
835 on_backtracking(_). | |
836 on_backtracking(P) :- P, !, fail. | |
837 | |
838 | |
839 %% bt_call( :Do, :Undo) is nondet. | |
840 % | |
841 % Creates a backtrackable operation from a non-backtrackable Do | |
842 % operation and a corresponding operation to undo it. Do can | |
843 % be non-deterministic, in which case bt_call(Do,Undo) will also | |
844 % have multiple solutions. Undo is called inside once/1. | |
845 % | |
846 % bt_call/2 is implemented both as a predicate and as a goal | |
847 % expansion (see goal_expansion/2). | |
848 bt_call(Do,Undo) :- Do, (true; once(Undo), fail). | |
849 | |
850 user:goal_expansion( bt_call(Do,Undo), (Do, (true; once(Undo), fail))). | |
851 | |
852 | |
853 | |
854 /* Might include these at some point | |
855 | |
856 % apply lambda term to another term | |
857 app(X\\F,Y,G) :- !, copy_term(X\\F,Y\\G). | |
858 app(T,A,Z) :- addargs(T,[A],Z). | |
859 app(T,A,B,Z) :- addargs(T,[A,B],Z). | |
860 app(T,A,B,C,Z) :- addargs(T,[A,B,C],Z). | |
861 | |
862 applist(F,N,A,Z) :- length(Z,N), maplist(app(F),A,Z). | |
863 applist(F,N,A,B,Z) :- length(Z,N), maplist(app(F),A,B,Z). | |
864 applist(F,N,A,B,C,Z) :- length(Z,N), maplist(app(F),A,B,C,Z). | |
865 | |
866 */ | |
867 | |
868 | |
869 % ------------------ DATABASE ------------------------------ | |
870 | |
871 %% bt_assert(Clause) is det. | |
872 % Backtrackable assert. | |
873 bt_assert(H) :- bt_call(assert(H),retract(H)). | |
874 | |
875 %% bt_retract(Clause) is det. | |
876 % Backtrackable retract. | |
877 bt_retract(H) :- bt_call(retract(H), assert(H)). | |
878 | |
879 %% strict_assert(Fact) is semidet. | |
880 % | |
881 % Asserts fact only if it is not already true. Fails | |
882 % if fact is already provable. Retracts fact on backtracking. | |
883 strict_assert(H) :- \+call(H), bt_call(assert(H),retract(H)). | |
884 | |
885 | |
886 %% strict_retract(Fact) is semidet. | |
887 % | |
888 % Retracts fact only if it is currently in the database. Fails | |
889 % if fact is not provable. Reasserts fact on backtracking. | |
890 strict_retract(H) :- call(H), bt_call(retract(H), assert(H)). | |
891 | |
892 | |
893 % when loaded, this sets the hostname/1 predicate. | |
894 :- dynamic hostname/1. | |
895 | |
896 %% hostname( -A:atom) is det. | |
897 % | |
898 % Unifies A with the computer's hostname. This is set when the | |
899 % module is loaded by calling the system command 'hostname -s'. | |
900 | |
901 % init_hostname is det - read hostname from UNIX command hostname. | |
902 init_hostname :- | |
903 setup_call_cleanup( | |
904 open(pipe('hostname -s'),read,SID), | |
905 (read_line_to_codes(SID,C), atom_codes(H,C), retractall(hostname(_)), assert(hostname(H))), | |
906 close(SID)). | |
907 | |
908 :- ( hostname(H) | |
909 -> format('% hostname already set to ~w\n',[H]) | |
910 ; init_hostname, hostname(H), format('% hostname set to ~w\n',[H]) | |
911 ). | |
912 | |
913 % Comma lists | |
914 % ie, lists built up using (,) as a pairing functor | |
915 % Note, these functor lists do NOT have a nil element - the | |
916 % last item in the list is the 2nd argument to the final | |
917 % functor term, which can therefore be a term headed by any | |
918 % other functor. Eg: | |
919 % (1,(2,3)) <-> [1,2,3] | |
920 % (1,(2,(3+4)) <-> [1,2,(3+4)] | |
921 | |
922 %% cl_list( +CL:clist(A), -L:list(A)) is det. | |
923 %% cl_list( -CL:clist(A), +L:list(A)) is det. | |
924 % | |
925 % Convert between comma lists and ordinary lists | |
926 cl_list((A,B),[A|BL]) :- cl_list(B,BL). | |
927 cl_list(A,[A]) :- A\=(_,_). | |
928 | |
929 %% cl_length( +L:clist, -N:natural) is det. | |
930 %% cl_length( -L:clist, +N:natural) is det. | |
931 % | |
932 % Length of a comma-list. | |
933 cl_length((_,B),N) :- cl_length(B,M), succ(M,N). | |
934 cl_length(X,1) :- X\=(_,_). | |
935 | |
936 | |
937 %% cl_list_vt( +CL:clist(A), -L:list(A)) is det. | |
938 %% cl_list_vt( -CL:clist(A), +L:list(A)) is det. | |
939 % | |
940 % Convert between comma lists (with open tails) and ordinary lists. | |
941 cl_list_vt(FL,[FL]) :- var(FL), !. | |
942 cl_list_vt(FL,[A|BL]) :- FL = (A,B), cl_list_vt(B,BL). | |
943 cl_list_vt(A,[A]) :- A\=(_,_). | |
944 | |
945 | |
946 %% cl_length_vt( +L:clist, -N:natural) is det. | |
947 %% cl_length_vt( -L:clist, +N:natural) is det. | |
948 % | |
949 % Length of a comma-list with possible variable tail. | |
950 % This version handles lists where the last element is variable (counts as 1) | |
951 cl_length_vt(FL,1) :- var(FL), !. | |
952 cl_length_vt(FL,N) :- FL=(_,B), cl_length_vt(B,M), succ(M,N). | |
953 cl_length_vt(FL,1) :- FL\=(_,_). | |
954 | |
955 %% cl_member(-X, +L:clist) is nondet. | |
956 % List membership for comma lists. | |
957 cl_member(X,(X,_)). | |
958 cl_member(X,(_,T)) :- cl_member(X,T). | |
959 cl_member(X,X) :- X\=(_,_). | |
960 |