Mercurial > hg > plml
changeset 9:60b7b78b3167
Removed utility Prolog libraries, which are now a prerequisite (package plcore);
Moved cellmap.m from matlab/general to matlab/db/dbcellmap.m.
author | samer |
---|---|
date | Fri, 20 Jan 2012 16:46:57 +0000 |
parents | 173e1c48e335 |
children | 7947baf7a624 |
files | INSTALL matlab/Makefile matlab/general/cellmap.m prolog/Makefile prolog/dcgu.pl prolog/ops.pl prolog/plml.pl prolog/update prolog/utils.pl |
diffstat | 9 files changed, 5 insertions(+), 1993 deletions(-) [+] |
line wrap: on
line diff
--- a/INSTALL Thu Jan 19 15:23:35 2012 +0000 +++ b/INSTALL Fri Jan 20 16:46:57 2012 +0000 @@ -21,6 +21,9 @@ that comes with SWI. This only has a hope of working on Unix systems, and I've only tried with Mac OS X and Linux. +You also need the plcore package, which contains the required Prolog +libraries utils.pl, dcgu.pl and ops.pl. + *** Binary and Prolog code ***
--- a/matlab/Makefile Thu Jan 19 15:23:35 2012 +0000 +++ b/matlab/Makefile Fri Jan 20 16:46:57 2012 +0000 @@ -2,5 +2,4 @@ install: install -d $(INSTALL_ML_TO) cp -pR db $(INSTALL_ML_TO) - cp -pR general $(INSTALL_ML_TO)
--- a/matlab/general/cellmap.m Thu Jan 19 15:23:35 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ -function Y=cellmap(fn,X) -% cellmap - Map a function over a cell array -% -% cellmap :: (A->B, {[Size]->A}) -> {[Size]->B} - -% preallocate to fix size -Y=cell(size(X)); -for i=1:numel(X) - Y{i}=feval(fn,X{i}); -end
--- a/prolog/Makefile Thu Jan 19 15:23:35 2012 +0000 +++ b/prolog/Makefile Fri Jan 20 16:46:57 2012 +0000 @@ -1,8 +1,5 @@ install: install -d $(INSTALL_PL_TO) - install $(INSTALL_FLAGS) -m 644 ops.pl $(INSTALL_PL_TO) install $(INSTALL_FLAGS) -m 644 plml.pl $(INSTALL_PL_TO) - install $(INSTALL_FLAGS) -m 644 utils.pl $(INSTALL_PL_TO) - install $(INSTALL_FLAGS) -m 644 dcgu.pl $(INSTALL_PL_TO)
--- a/prolog/dcgu.pl Thu Jan 19 15:23:35 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,953 +0,0 @@ -:- module(dcgu, [ - writedcg/1 - - , nop/2 - , out//1 - , (>>)//2 - , (\<)//1 - , (\>)//1 - , (\#)//2 - , run_left//3 - , run_right//3 - , trans//2 - - , maybe//1 - , opt//1 - , if//3, if//2 - , parmap//2, parmap//3, parmap//4, parmap//5, parmap//6 - , seqmap//2, seqmap//3, seqmap//4, seqmap//5, seqmap//6 - , seqmap_n//3, seqmap_n//4, seqmap_n//5 - , seqmap_with_sep//3 - , seqmap_with_sep//4 - , seqmap_with_sep//5 - , seqmap_ints//3 - , seqmap_args//4 - , seqmap_args//5 - , seqmap_args//6 - , iterate//3 - %, apply/4, apply/5 - , seq//1, seq//2, seq_n//3 - , smap//2 - , rep//2, rep_nocopy//2 - , at//1, wr//1, str//1, fmt//2 - , brace//1, paren//1, sqbr//1 - , q//1, qq//1 - , escape//2, escape_with//3 - , null//0, cr//0, sp//0, fs//0 - , fssp/2, tb/2, comma/2, commasp/2 - , padint/5 - - , do_then_call/5 - , do_then_call/6 - , do_then_call/7 - - , any/3, notany/3, arb/2, arbno/3, bal/2 - , span/3, break/3, len/3 - , exhaust/3 - , set/3, get/3, set_with/3 - , with/4, iso/3 - , once/3 - , repeat/2 - , (//)//2 - , until//2 - - , findall//3 - , setof//3 - - , op(900,fy,\<) - , op(900,fy,\>) - , op(900,xfy,\#) - - , lift//1 - , lift//2 - , lift//3 -]). - -/** <module> DCG utilities - -This module contains predicates for working with definite clause -grammars and the related stateful programming style where state -arguments are automatically threaded through sequences -of calls. Some useful DCG procedures are also included. - -When a predicate is declared with type =|foo(...)// is Det|=, -any requirements on the type of the DCG state are hidden, i.e. the -types of the two extra arguments are hidden. In these cases, -the documentation below will sometimes state that the predicate -'runs in the =|S|= DCG'. - ----+++ Types used in this module - -We use the following to denote types of terms that can -be interpreted as DCG phrases with or without further -arguments. - * phrase(S) - If P is a term of type =|phrase(S)|=, then P is a valid DCG phrase - when the DCG state is of type =|S|=, i.e. =|phrase(P,S1,S2)|= is - valid Prolog goal when S1 and S2 are of type =|S|=. N.B. the type - =|phrase(S)|= is almost but not quite equivalent to the binary - predicate type =|pred(S,S)|=. All such predicates are valid phrases, - but phrases involving braces (e.g. {Goal}), commas, semicolons, - and if-then constructs (->) are not equivalent to predicates - with two extra arguments. - * phrase(A,S) - If P is of type =|phrase(A,S)|= and X has type A, then =|call(P,X)|= - is a valid DCG phrase when the DCG is of type S. This type _|is|_ - equivalent to =|pred(A,S,S)|= because the only way to call it - is with call//1 inside a DCG or call/3 outside it. - * phrase(A,B,S) - If P is of type =|phrase(A,B)|= and =|X|= and =|Y|= are of types - =|A|= and =|B|= respectively, then =|call(P,X,Y)|= - is a valid DCG phrase. And so on. You get the idea. - -The type =|pair(A,B)|= will be used to denote the type of terms -with functor (,)/2 and arguments of types =|A|= and =|B|= respectively: -== -pair(A,B) ---> (A,B). -== -This type is used to support a set of general purpose predicates -for combining commands in two distinct DCGs into a single DCG -over a product space of states. -*/ - -:- use_module(library(ops)). - -:- module_transparent seq/3, seq/4, smap/4. - -:- meta_predicate - writedcg(2) - , if(0,0,0,?,?) - , if(0,0,?,?) - , maybe(2,?,?) - , opt(2,?,?) - , once(2,?,?) - , repeat(?,?) - , >>(2,2,?,?) - , //(2,?,?,?) - , \<(2,?,?) - , \>(2,?,?) - , \#(?,2,?,?) - , brace(2,?,?) - , paren(2,?,?) - , sqbr(2,?,?) - , qq(2,?,?) - , q(2,?,?) - , arbno(2,?,?) - , rep(?,2,?,?) - , rep_nocopy(+,2,?,?) - , exhaust(2,?,?) - , with(?,2,?,?) - , iso(2,?,?) - , set_with(1,?,?) - , run_left(2,?,?,?,?) - , run_right(2,?,?,?,?) - , iterate(2,?,?,?,?) - , parmap(1,?,?,?) - , parmap(2,?,?,?,?) - , parmap(3,?,?,?,?,?) - , parmap(4,?,?,?,?,?,?) - , parmap(5,?,?,?,?,?,?,?) - , seqmap(1,?,?,?) - , seqmap(2,?,?,?,?) - , seqmap(3,?,?,?,?,?) - , seqmap(4,?,?,?,?,?,?) - , seqmap(5,?,?,?,?,?,?,?) - , seqmap_n(+,1,?,?,?) - , seqmap_n(+,2,?,?,?,?) - , seqmap_n(+,3,?,?,?,?,?) - , seqmap_ints(1,+,+,?,?) - , seqmap_with_sep(0,1,?,?,?) - , seqmap_with_sep(0,2,?,?,?,?) - , seqmap_with_sep(0,3,?,?,?,?,?) - , seqmap_args(1,+,+,?,?,?) - , seqmap_args(2,+,+,?,?,?,?) - , seqmap_args(3,+,+,?,?,?,?,?) - , do_then_call(0,1,?,?,?) - , do_then_call(0,2,?,?,?,?) - , do_then_call(0,3,?,?,?,?,?) - , until(0,2,?,?) - . - -:- op(900,fy,\<). -:- op(900,fy,\>). -:- op(900,xfy,\#). - - -%%% -%%% The first lot of stuff is completely general for any stateful system. -%%% - - -%% trans( ?Old:S, ?New:S, ?S1:S, ?S2:S) is det. -% -% Unifies Old and New with the states S1 and S2 respectively. -trans(X,Y,X,Y). - -% these will be useful for seq (they define a sort of generalised -% lazy mapping over sequences of DCG terms) -empty([]). -empty(_:[]). -empty(map(_,L)) :- empty(L). -empty(_:map(_,L)) :- empty(L). -empty(M..N) :- N<M. - -singleton([H|T],H) :- empty(T). -singleton(M:[H|T],M:H) :- empty(T). -singleton(map(F,L),call(F,H)) :- singleton(L,H). -singleton(M:map(F,L),call(M:F,H)) :- singleton(L,H). -singleton(M..M,M). - -properlist([H|T],H,T) :- \+empty(T). -properlist(M:[H|T],M:H,M:T) :- \+empty(T). -properlist(map(F,L),call(F,H),map(F,T)) :- properlist(L,H,T). -properlist(M:map(F,L),call(M:F,H),M:map(F,T)) :- properlist(L,H,T). -properlist(M..N,M,M1..N) :- N>M, succ(M,M1). - -%% nop// is det. -% -% Do nothing. (More neutral than []). -nop(X,X). - -%% set(S:A, S1:_, S2:A) is det. -% Set state to S. Implemented by goal expansion. -set(S,_,S). - -%% get(S:A, S1:A, S2:A) is det. -% Get state to S. Implemented by goal expansion. -get(S,S,S). - -%% with(S:A, P:phrase(A), S1:B, S2:B) is nondet. -% -% Run phrase P starting from state S and discarding -% the final state, meanwhile preserving the state -% of the current system, i.e. guarantees S1=S2. -with(S,G) --> {phrase(G,S,_)}. - -%% iso(P:phrase(A), S1:A, S2:A) is nondet. -% -% Run phrase P starting with current state but discarding -% its final state and preserving the current state, so -% that S1=S2. -iso(G) --> get(S), {phrase(G,S,_)}. - -%% set_with(+G:pred(A), S1:_, S2:A) is det. -% -% Set current state using a given callable goal G, which should accept one argument. -% should be of type pred( -S:A), ie it should set S to the new desired -% state, which is installed in the DCG state. -set_with(G,_,S) :- call(G,S). - -%% \<(P:phrase(A), ?S1:pair(A,B), ?S2:pair(A,B)) is nondet. -% -% Apply phrase P to left part of a paired state. -% Implemented by goal expansion so incurs only very small -% speed penalty. -\<(P,(A1,B),(A2,B)) :- phrase(P,A1,A2). - -%% \>(P:phrase(B), ?S1:pair(A,B), ?S2:pair(A,B)) is nondet. -% -% Apply phrase P which must be of type pred(B,B) to right -% part of a paired state. -% Implemented by goal expansion so incurs only very small -% speed penalty. -\>(P,(A,B1),(A,B2)) :- phrase(P,B1,B2). - -%% run_left(P:phrase(pair(A,B)), ?A1:A, ?A2:A, ?B1:B, ?B2:B) is multi. -% -% Applies DCG phrase P to state formed by pairing A1 and A2 with -% current DCG states B1 and B2. Phrase can use (\<) to access the -% A state and (\>) to access the underlying B state. -run_left(P,S1,S2,T1,T2) :- phrase(P,(S1,T1),(S2,T2)). - -%% run_right(P:phrase(pair(A,B)), ?B1:B, ?B2:B, ?A1:A, ?A2:A) is multi. -% -% Applies DCG phrase P to state formed by pairing A1 and A2 with -% current DCG states B1 and B2. Phrase can use (\<) to access the -% A state and (\>) to access the underlying B state. -run_right(P,S1,S2,T1,T2) :- phrase(P,(T1,S1),(T2,S2)). - -%% \#(N:natural, P:phrase(A), ?S1, ?S2) is nondet. -% -% Apply phrase P to the Nth argument of state which must -% be a compound term (with arbitrary functor), with the -% Nth argument of type A. -\#(N, P, S1, S2) :- with_nth_arg(N,P,S1,S2). - - -system:goal_expansion( run_left(P,S1,S2,T1,T2), phrase(P,(S1,T1),(S2,T2))). -system:goal_expansion( run_right(P,S1,S2,T1,T2), phrase(P,(T1,S1),(T2,S2))). -system:goal_expansion( \<(P,S1,S2), (S1=(L1,R),S2=(L2,R),phrase(P,L1,L2)) ). -system:goal_expansion( \>(P,S1,S2), (S1=(L,R1),S2=(L,R2),phrase(P,R1,R2)) ). -system:goal_expansion( nop(S1,S2), (S1=S2) ). -system:goal_expansion( out(X,S1,S2), (S1=[X|S2]) ). -system:goal_expansion( get(S,S1,S2), (S=S1,S1=S2) ). -system:goal_expansion( set(S,_,S2), (S=S2) ). -system:goal_expansion( A >> B, (A,B) ). -system:goal_expansion( set_with(C,_,S2), Call) :- mk_call(C,[S2],Call). -system:goal_expansion( trans(A1,A2,S1,S2), (S1=A1,S2=A2) ). -system:goal_expansion( //(P1,P2,S1,S2), (G1,G2)) :- - nonvar(P1), P1=..[F1|A1], append(A1,[S1,S2],B1), G1=..[F1|B1], - nonvar(P2), P2=..[F2|A2], append(A2,[S1,S2],B2), G2=..[F2|B2]. - -mk_call(C,XX,Call) :- var(C), !, mk_call(call(C),XX,Call). -mk_call(M:C,XX,M:Call) :- !, mk_call(C,XX,Call). -mk_call(C,XX,Call) :- C =.. CL, append(CL,XX,CL2), Call =.. CL2. - - -%% pushl(S:A,S1:B,S2:pair(A,B)) is det. -% Create a paired state by putting S on the left and the -% old state on the right. -pushl(S,S0,(S,S0)). - -%% pushr(S:A,S1:B,S2:pair(B,A)) is det. -% Create a paired state by putting S on the right and the -% old state on the left. -pushr(S,S0,(S0,S)). - -%% popl(S:A,S1:pair(A,B),S2:B) is det. -% Unpair state by removing left state and unifying it with S. -popl(S,(S,S0),S0). - -%% popr(S:A,S1:(B,A),S2:B) is det. -% Unpair state by removing right state and unifying it with S. -popr(S,(S0,S),S0). - -%% >>(G1:phrase(S), G2:phrase(S))// is nondet. -% Sequential conjuction of phrases G1 and G2, equivalent to (G1,G2), -% but sometimes more convenient in terms of operator priorities. -% Implemented by goal expansion. -A >> B --> A, B. - -%% once(G:phrase(_))// is semidet. -% Call DCG phrase G succeeding at most once. -once(G,A,B) :- once(phrase(G,A,B)). - -%% repeat// is nondet. -% Create an infinite number of choice points. -repeat(A,A) :- repeat. - -%% maybe(P:phrase(_))// is det. -% Try P, if it fails, then do nothing. If it succeeds, -% cut choicepoints and continue. -maybe(P) --> P -> nop; nop. - -%% opt(P:phrase(_))// is nondet. -% P or nothing. Like maybe but does not cut if P succeeds. -opt(P) --> P; nop. - -%% if(G:pred,P,Q)// is det. -%% if(G:pred,P)// is det. -% -% If Prolog goal =|call(G)|= succeeds, do P, otherwise, do Q. -% if(G,P) is equivalent to if(G,P,nop), i.e. does nothing -% if P fails. -if(A,B,C) --> {nonvar(A), call(A)} -> B; C. -if(A,B) --> if(A,B,nop). - - -%% exhaust( P:phrase(_))// is det. -% -% Run phrase sequentially as many times as possible until it fails. -% Any choice points left by G are cut. -exhaust(G) --> G -> exhaust(G); nop. - - -%% until( +Q:pred, +P:phrase(_))// is det. -% -% Repeatedly call phrase P and test ordinary Prolog goal -% Q until Q fails. P and Q are copied together before each -% iteration, so variables can be shared between them, but -% are not shared between iterations. -until( Pred, Op) --> - {copy_term(Pred/Op,Pred1/Op1)}, - call(Op1), - ( {call(Pred1)} - -> {Pred/Op=Pred1/Op1} - ; until(Pred, Op) - ). - -%% iterate( +P:phrase(A,A,S), +X:A, -Y:A)// is nondet. -% -% Sequentially call P zero or more times, passing in X on -% the first call and threading the result through subsequent calls, -% (as well as threading the DCG state in the normal way) -% ending in Y. - -iterate(_,A,A) --> []. -iterate(F,A1,A3) --> call(F,A1,A2), iterate(F,A2,A3). - - -%% rep( +N:natural, +P:phrase(_))// is nondet. -%% rep( -N:natural, +P:phrase(_))// is nondet. -% -% Equivalent to N sequential copies of phrase P. -% Free variables in P are *not* shared between copies. -% If N is unbound on entry, rep//2 is _cautious_: it tries -% gradually increasing N from 0 on backtracking. - -rep(N,G,S1,S2) :- - ( var(N) - -> rep_var(N,G,S1,S2) - ; rep_nonvar(N,G,S1,S2) - ). - -rep_var(0,_,S,S). -rep_var(N,G,S1,S3) :- - copy_term(G,G1), phrase(G1,S1,S2), - rep_var(M,G,S2,S3), succ(M,N). - -rep_nonvar(0,_,S,S) :- !. -rep_nonvar(N,G,S1,S3) :- - copy_term(G,G1), phrase(G1,S1,S2), - succ(M,N), rep_nonvar(M,G,S2,S3). - - -%% rep_nocopy( +N:natural, +P:phrase(_))// is nondet. -% -% Like rep//2 but does not copy P before calling, so -% any variables in P are shared between all calls. -% Also, N cannot be a variable in this implementation. -rep_nocopy(0,_) --> !. -rep_nocopy(N,P) --> call(P), {succ(M,N)}, rep_nocopy(M,P). - - -%% seq( +L:plist, +Sep)// is nondet. -%% seq( +L:plist)// is nondet. -% Sequence list of phrases with separator. L can be a sort of _generalised_ -% list of phrases, which can be: -% == -% plist ---> list(A) % ordinary list -% ; map(phrase(B),plist) % map phrase head P over list -% . -% == -% Sep is inserted strictly betweened elements of L. seq(L) is equivalent -% to seq(L,nop). - -seq(L,_) --> {dcgu:empty(L)}. -seq(L,_) --> {dcgu:singleton(L,H)}, H. -seq(L,S) --> {dcgu:properlist(L,H,T)}, H, S, seq(T,S). -seq(L) --> seq(L,nop). % if no separator specified, use nop. - - -%% seq_n( N:natural, +L:plist, +Sep)// is nondet. -% Sequence list of phrases with separator and counting. -% -% @see seq//2. - -seq_n(0,L,_) --> {dcgu:empty(L)}. -seq_n(1,L,_) --> {dcgu:singleton(L,H)}, H. -seq_n(N,L,S) --> {dcgu:properlist(L,H,T)}, H, S, seq_n(M,T,S), {succ(M,N)}. - -%% smap(+F,+L:list)// is nondet. -% Equivalent to seq(map(F,L),nop). -smap(F,L) --> seq(map(F,L),nop). - - - -%% seqmap( +P:phrase(A,S), X:list(A))// is nondet. -%% seqmap( +P:phrase(A,B,S), X:list(A), Y:list(B))// is nondet. -%% seqmap( +P:phrase(A,B,C,S), X:list(A), Y:list(B), Z:list(C))// is nondet. -%% seqmap( +P:phrase(A,B,C,D,S), X:list(A), Y:list(B), Z:list(C), W:list(D))// is nondet. -%% seqmap( +P:phrase(A,B,C,D,E,S), X:list(A), Y:list(B), Z:list(C), W:list(D), V:list(E))// is nondet. -% -% seqmap//N is like maplist/N except that P is an incomplete _phrase_ -% rather an ordinary goal, which is applied to the elements of the supplied -% lists _|in order|_, while threading the DCG state correctly through all -% the calls. -% -% seqmap//N is very powerful - it is like =foldl= and =mapaccum= in functional -% languages, but with the added flexibility of bidirectional Prolog variables. -% -% @see maplist/2. - -seqmap(_,[]) --> []. -seqmap(P,[A|AX]) --> call(P,A), seqmap(P,AX). -seqmap(_,[],[]) --> []. -seqmap(P,[A|AX],[B|BX]) --> call(P,A,B), seqmap(P,AX,BX). -seqmap(_,[],[],[]) --> []. -seqmap(P,[A|AX],[B|BX],[C|CX]) --> call(P,A,B,C), seqmap(P,AX,BX,CX). -seqmap(_,[],[],[],[]) --> []. -seqmap(P,[A|AX],[B|BX],[C|CX],[D|DX]) --> call(P,A,B,C,D), seqmap(P,AX,BX,CX,DX). -seqmap(_,[],[],[],[],[]) --> []. -seqmap(P,[A|AX],[B|BX],[C|CX],[D|DX],[E|EX]) --> call(P,A,B,C,D,E), seqmap(P,AX,BX,CX,DX,EX). - -true(_,_). -parmap(_,[]) --> true. -parmap(P,[A|AX]) --> call(P,A) // parmap(P,AX). -parmap(_,[],[]) --> true. -parmap(P,[A|AX],[B|BX]) --> call(P,A,B) // parmap(P,AX,BX). -parmap(_,[],[],[]) --> true. -parmap(P,[A|AX],[B|BX],[C|CX]) --> call(P,A,B,C) // parmap(P,AX,BX,CX). -parmap(_,[],[],[],[]) --> true. -parmap(P,[A|AX],[B|BX],[C|CX],[D|DX]) --> call(P,A,B,C,D) // parmap(P,AX,BX,CX,DX). -parmap(_,[],[],[],[],[]) --> true. -parmap(P,[A|AX],[B|BX],[C|CX],[D|DX],[E|EX]) --> call(P,A,B,C,D,E) // parmap(P,AX,BX,CX,DX,EX). - -%% seqmap_n( +N:natural, +P:phrase(A), X:list(A))// is nondet. -%% seqmap_n( +N:natural, +P:phrase(A,B), X:list(A), Y:list(B))// is nondet. -%% seqmap_n( +N:natural, +P:phrase(A,B,C), X:list(A), Y:list(B), Z:list(C))// is nondet. -% -% seqmap_n//.. is like seqmap/N except that the lists of arguments are of lenght N. - -seqmap_n(0,_,[]) --> []. -seqmap_n(N,P,[A|AX]) --> {succ(M,N)}, call(P,A), seqmap_n(M,P,AX). -seqmap_n(0,_,[],[]) --> []. -seqmap_n(N,P,[A|AX],[B|BX]) --> {succ(M,N)}, call(P,A,B), seqmap_n(M,P,AX,BX). -seqmap_n(0,_,[],[],[]) --> []. -seqmap_n(N,P,[A|AX],[B|BX],[C|CX]) --> {succ(M,N)}, call(P,A,B,C), seqmap_n(M,P,AX,BX,CX). - - -/* - * Goal expansions - */ - -cons(A,B,[A|B]). - -expand_seqmap_with_prefix(Sep0, Callable0, SeqmapArgs, Goal) :- - ( Callable0 = M:Callable - -> NextGoal = M:NextCall - ; Callable = Callable0, - NextGoal = NextCall - ), - - append(Lists, [St1,St2], SeqmapArgs), - - Callable =.. [Pred|Args], - length(Args, Argc), - length(Argv, Argc), - length(Lists, N), - length(Vars, N), - MapArity is N + 4, - format(atom(AuxName), '__aux_seqmap/~d_~w_~w+~d', [MapArity, Sep0, Pred, Argc]), - build_term(AuxName, Lists, Args, St1, St2, Goal), - - AuxArity is N+Argc+2, - prolog_load_context(module, Module), - ( current_predicate(Module:AuxName/AuxArity) - -> true - ; rep(N,[[]],BaseLists,[]), - length(Anon, Argc), - build_term(AuxName, BaseLists, Anon, S0, S0, BaseClause), - - length(Vars,N), - maplist(cons, Vars, Tails, NextArgs), - ( Sep0=_:Sep -> true; Sep=Sep0 ), - ( is_list(Sep) -> append(Sep,S2,S1), NextThing=NextGoal - ; build_term(phrase, [Sep0], [], S1, S2, NextSep), - NextThing = (NextSep,NextGoal) - ), - build_term(Pred, Argv, Vars, S2, S3, NextCall1), - build_term(AuxName, Tails, Argv, S3, S4, NextIterate), - build_term(AuxName, NextArgs, Argv, S1, S4, NextHead), - - ( goal_expansion(NextCall1,NextCall) -> true - ; NextCall1=NextCall), - - NextClause = (NextHead :- NextThing, NextIterate), - - ( predicate_property(Module:NextGoal, transparent) - -> compile_aux_clauses([ (:- module_transparent(Module:AuxName/AuxArity)), - BaseClause, - NextClause - ]) - ; compile_aux_clauses([BaseClause, NextClause]) - ) - ). - -expand_call_with_prefix(Sep0, Callable0, InArgs, (SepGoal,CallGoal)) :- - append(CallArgs, [S1,S3], InArgs), - - ( Sep0=_:Sep -> true; Sep=Sep0 ), - ( is_list(Sep) -> append(Sep,S2,SS), SepGoal=(S1=SS) - ; build_term(phrase, [Sep0], [], S1, S2, SepGoal) - ), - - ( var(Callable0) - -> build_term(call,[Callable0], CallArgs, S2, S3, CallGoal1) - ; ( Callable0 = M:Callable - -> CallGoal1 = M:NextCall - ; Callable = Callable0, - CallGoal1 = NextCall - ), - Callable =.. [Pred|Args], - build_term(Pred, Args, CallArgs, S2, S3, NextCall) - ), - ( goal_expansion(CallGoal1,CallGoal) -> true - ; CallGoal1=CallGoal - ). - -seqmap_with_sep_first_call(P,[A1|AX],AX) --> call(P,A1). -seqmap_with_sep_first_call(P,[A1|AX],[B1|BX],AX,BX) --> call(P,A1,B1). -seqmap_with_sep_first_call(P,[A1|AX],[B1|BX],[C1|CX],AX,BX,CX) --> call(P,A1,B1,C1). - -expand_seqmap_with_sep(Sep, Pred, SeqmapArgs, (dcgu:FirstCall,dcgu:SeqmapCall)) :- - prolog_load_context(module,Context), - (Sep=SMod:Sep1 -> true; SMod=Context, Sep1=Sep), - (Pred=CMod:Pred1 -> true; CMod=Context, Pred1=Pred), - append(Lists, [St1,St3], SeqmapArgs), - length(Lists, N), - length(Tails, N), - build_term(seqmap_with_sep_first_call, [CMod:Pred1|Lists], Tails, St1, St2, FirstCall), - build_term(seqmap_with_prefix, [SMod:Sep1,CMod:Pred1], Tails, St2, St3, SeqmapCall). - -build_term(H,L1,L2,S1,S2,Term) :- - append(L2,[S1,S2],L23), - append(L1,L23,L123), - Term =.. [H | L123]. - - -expand_dcgu(Term, Goal) :- - functor(Term, seqmap, N), N >= 4, - Term =.. [seqmap, Callable | Args], - callable(Callable), !, - expand_seqmap_with_prefix([],Callable, Args, Goal). - -expand_dcgu(Term, Goal) :- - functor(Term, seqmap_with_sep, N), N >= 5, - Term =.. [seqmap_with_sep, Sep, Callable | Args], - nonvar(Sep), callable(Callable), !, - expand_seqmap_with_sep(Sep, Callable, Args, Goal). - -expand_dcgu(Term, Goal) :- - functor(Term, seqmap_with_prefix, N), N >= 5, - Term =.. [seqmap_with_prefix, Sep, Callable | Args], - callable(Callable), nonvar(Sep), !, - expand_seqmap_with_prefix(Sep, Callable, Args, Goal). - -expand_dcgu(Term, Goal) :- - functor(Term, do_then_call, N), N >= 2, - Term =.. [do_then_call, Prefix, Callable | Args], - nonvar(Prefix), !, - expand_call_with_prefix(Prefix, Callable, Args, Goal). - -system:goal_expansion(GoalIn, GoalOut) :- - \+current_prolog_flag(xref, true), - expand_dcgu(GoalIn, GoalOut). -% prolog_load_context(module,Mod), -% writeln(expanded(Mod:GoalIn)). - - -%% seqmap_with_sep(+S:phrase, +P:phrase(A), X:list(A))// is nondet. -%% seqmap_with_sep(+S:phrase, +P:phrase(A,B), X:list(A), Y:list(B))// is nondet. -%% seqmap_with_sep(+S:phrase, +P:phrase(A,B,C), X:list(A), Y:list(B), Z:list(C))// is nondet. -% -% As seqmap//2.. but inserting the separator phrase S between each call to P. -% NB: *Fails* for empty lists. -% -% @see seqmap//2 -%seqmap_with_sep(S,P,[A|AX]) --> call(P,A), seqmap_with_prefix(S,P,AX). -%seqmap_with_sep(S,P,[A|AX],[B|BX]) --> call(P,A,B), seqmap_with_prefix(S,P,AX,BX). -%seqmap_with_sep(S,P,[A|AX],[B|BX],[C|CX]) --> call(P,A,B,C), seqmap_with_prefix(S,P,AX,BX,CX). -seqmap_with_sep(S,P,[A|AX]) --> call(P,A), seqmap(do_then_call(S,P),AX). -seqmap_with_sep(S,P,[A|AX],[B|BX]) --> call(P,A,B), seqmap(do_then_call(S,P),AX,BX). -seqmap_with_sep(S,P,[A|AX],[B|BX],[C|CX]) --> call(P,A,B,C), seqmap(do_then_call(S,P),AX,BX,CX). - -%seqmap_with_prefix(_,_,[]) --> []. -%seqmap_with_prefix(S,P,[A|AX]) --> S, call(P,A), seqmap_with_prefix(S,P,AX). -%seqmap_with_prefix(_,_,[],[]) --> []. -%seqmap_with_prefix(S,P,[A|AX],[B|BX]) --> S, call(P,A,B), seqmap_with_prefix(S,P,AX,BX). -%seqmap_with_prefix(_,_,[],[],[]) --> []. -%seqmap_with_prefix(S,P,[A|AX],[B|BX],[C|CX]) --> S, call(P,A,B,C), seqmap_with_prefix(S,P,AX,BX,CX). - - -% do_then_call( +S:phrase, +P:phrase(A), X:A)// is nondet. -% do_then_call( +S:phrase, +P:phrase(A,B), X:A, Y:B)// is nondet. -% do_then_call( +S:phrase, +P:phrase(A,B,C), X:A, Y:B, Z:C)// is nondet. -% -% Call phrase S, then call phrase P with arguments A, B, C etc. -do_then_call(S,P,A) --> S, call(P,A). -do_then_call(S,P,A,B) --> S, call(P,A,B). -do_then_call(S,P,A,B,C) --> S, call(P,A,B,C). - - -%% seqmap_ints( +P:phrase(integer), +I:integer, +J:integer)// is nondet. -% -% Equivalent to seqmap(P) applied to the list of integers from I to J inclusive. -% -% @see seqmap//2. -seqmap_ints(P,L,N) --> - ( {L>N} -> [] - ; {M is L+1}, call(P,L), seqmap_ints(P,M,N) - ). - - -%% seqmap_args( +P:phrase(integer), +I:integer, +J:integer, X:term)// is nondet. -%% seqmap_args( +P:phrase(integer), +I:integer, +J:integer, X:term, Y:term)// is nondet. -%% seqmap_args( +P:phrase(integer), +I:integer, +J:integer, X:term, Y:term, Z:term)// is nondet. -% -% Like seqmap//N, but applied to the arguments of term X, Y and Z, from the I th to the -% J th inclusive. -% -% @see seqmap//2. - -seqmap_args(P,L,N,A) --> - ( {L>N} -> [] - ; {succ(L,M), arg(L,A,AA)}, - call(P,AA), seqmap_args(P,M,N,A) - ). - -seqmap_args(P,L,N,A,B) --> - ( {L>N} -> [] - ; {succ(L,M), arg(L,A,AA), arg(L,B,BB)}, - call(P,AA,BB), seqmap_args(P,M,N,A,B) - ). - -seqmap_args(P,L,N,A,B,C) --> - ( {L>N} -> [] - ; {succ(L,M), arg(L,A,AA), arg(L,B,BB), arg(L,C,CC)}, - call(P,AA,BB,CC), seqmap_args(P,M,N,A,B,C) - ). - - - -%%% ------------------------------------------------------------------ -%%% These are for sequence building DCGs. -%%% ------------------------------------------------------------------ - - - -%% out(?X)// is det. -% -% Equivalent to [X]. prepends X to the difference list represented by -% the DCG state variables. -out(L,[L|L0],L0). - - -% SNOBOL4ish rules -% -% Others: -% maxarb -% pos rpos -% tab rtab -% rem - - -%% any(+L:list(_))// is nondet. -% Matches any element of L. -any(L) --> [X], {member(X,L)}. - -%% notany(+L:list(_))// is nondet. -% Matches anything not in L. -notany(L) --> [X], {maplist(dif(X),L)}. - -%% arb// is nondet. -% Matches an arbitrary sequence. Proceeds cautiously. -arb --> []; [_], arb. - -%% arbno(+P:phrase)// is nondet. -% Matches an arbitrary number of P. Proceeds cautiously. -% Any variables in P are shared across calls. -arbno(P) --> []; P, arbno(P). - -%% bal// is nondet. -% Matches any expression with balanced parentheses. -bal --> balexp, arbno(balexp). -balexp --> "(", bal, ")". -balexp --> notany("()"). - -%% span(+L:list(_))// is nondet. -% Matches the longest possible sequence of symbols from L. -span(L,A,[]) :- any(L,A,[]). -span(L) --> any(L), span(L). -span(L), [N] --> any(L), [N], { maplist( dif( N), L) }. - -%% break(+L:list(_))// is nondet. -% Matches the longest possible sequence of symbols not in L. -break(L,A,[]) :- notany(L,A,[]). -break(L) --> notany(L), break(L). -break(L), [N] --> notany(L), [N], { member(N,L) }. - -%% len(N:natural)// is nondet. -% Matches any N symbols. -len(0) --> []. -len(N) --> [_], ({var(N)} -> len(M), {succ(M,N)}; {succ(M,N)}, len(M)). - - -%% //(+P:phrase(A), ?C:list(A), ?S1:list(A), ?S2:list(A)) is nondet. -%% //(+P:phrase(A), +C:phrase(A), ?S1:list(A), ?S2:list(A)) is nondet. -% -% Sequence capture operator - captures the matching sequence C of any -% phrase P, eg. -% == -% ?- phrase(paren(arb)//C,"(hello)world",_) -% C = "(hello)". -% true -% == -% If nonvar(C) and C is a phrase, it is called after calling P. - -//(H,C,L,T) :- - ( var(C) - -> phrase(H,L,T), append(C,T,L) - ; phrase(H,L,T), phrase(C,L,T) - ). - -%%% ------------------------------------------------------------------ -%%% These are for character sequences DCGs. - -%% writedcg(+P:phrase) is nondet. -% -% Run the phrase P, which must be a standard list-of-codes DCG, -% and print the output. -writedcg(Phrase) :- - phrase(Phrase,Codes), - format('~s',[Codes]). - -%% null// is det. -% Empty string. -null --> "". - -%% cr// is det. -% Carriage return "\n". -cr --> "\n". - -%% sp// is det. -% Space " ". -sp --> " ". - -%% fs// is det. -% Full stop (period) ".". -fs --> ".". - -%% fssp// is det. -% Full stop (period) followed by space. -fssp --> ". ". - -%% tb// is det. -% Tab "\t". -tb --> "\t". - -%% comma// is det. -% Comma ",". -comma --> ",". - -%% commasp// is det. -% Comma and space ", ". -commasp --> ", ". - -%% at(X:atom)// is det. -% Generate code list for textual representation of atom X. -at(A,C,T) :- atomic(A), with_output_to(codes(C,T),write(A)). - -%% wr(X:term)// is det. -% Generate the list of codes for term X, as produced by write/1. -wr(X,C,T) :- ground(X), with_output_to(codes(C,T),write(X)). - -%% wq(X:term)// is det. -% Generate the list of codes for term X, as produced by writeq/1. -wq(X,C,T) :- ground(X), with_output_to(codes(C,T),writeq(X)). - -%% str(X:term)// is det. -% Generate the list of codes for string X, as produced by writeq/1. -str(X,C,T):- string(X), with_output_to(codes(C,T),write(X)). - -%% fmt(+F:atom,+Args:list)// is det -% Generate list of codes using format/3. -fmt(F,A,C,T) :- format(codes(C,T),F,A). - -%% brace(P:phrase)// is nondet. -% Generate "{" before and "}" after the phrase P. -brace(A) --> "{", A, "}". - -%% paren(P:phrase)// is nondet. -% Generate "(" before and ")" after the phrase P. -paren(A) --> "(", A, ")". - -%% sqbr(P:phrase)// is nondet. -% Generate "[" before and "]" after the phrase P. -sqbr(A) --> "[", A, "]". - -%% q(P:phrase(list(code)))// is nondet. -% Generate list of codes from phrase P, surrounds it with single quotes, -% and escapes (by doubling up) any internal quotes so that the -% generated string is a valid quoted string. Must be list of codes DCG. -q(X,[39|C],T) :- T1=[39|T], escape_with(39,39,X,C,T1). % 39 is ' - -%% qq(P:phrase(list(code)))// is nondet. -% Generate list of codes from phrase P, surrounds it with double quotes, -% and escapes (by doubling up) any double quotes so that the -% generated string is a valid double quoted string. -qq(X,[34|C],T) :- T1=[34|T], escape_with(34,34,X,C,T1). % 34 is " - -% escape difference list of codes with given escape character -escape_codes(_,_,A,A,A). -escape_codes(E,Q,[Q|X],[E,Q|Y],T) :-escape_codes(E,Q,X,Y,T). -escape_codes(E,Q,[A|X],[A|Y],T) :- Q\=A, escape_codes(E,Q,X,Y,T). - -%% escape_with(E:C, Q:C, P:phrase(list(C)))// is nondet. -% -% Runs phrase P to generate a list of elements of type C and -% then escapes any occurrences of Q by prefixing them with E, e.g., -% =|escape_with(92,39,"some 'text' here")|= escapes the single quotes -% with backslashes, yielding =|"some \'text\' here"|=. -escape_with(E,Q,Phrase,L1,L2) :- - phrase(Phrase,L0,L2), - escape_codes(E,Q,L0,L1,L2). - -%% escape(Q:C, P:phrase(list(C)))// is nondet. -% -% Runs phrase P to generate a list of elements of type C and -% then escapes any occurrences of Q by doubling them up, e.g., -% =|escape(39,"some 'text' here")|= doubles up the single quotes -% yielding =|"some ''text'' here"|=. -escape(Q,A) --> escape_with(Q,Q,A). - -%% padint( +N:integer, +Range, +X:integer)// is nondet. -% -% Write integer X padded with zeros ("0") to width N. -padint(N,L..H,X,C,T) :- - between(L,H,X), - format(atom(Format),'~~`0t~~d~~~d|',[N]), - format(codes(C,T),Format,[X]). - -difflength(A-B,N) :- unify_with_occurs_check(A,B) -> N=0; A=[_|T], difflength(T-B,M), succ(M,N). - -% tail recursive version -difflength_x(A-B,M) :- difflength_x(A-B,0,M). -difflength_x(A-B,M,M) :- unify_with_occurs_check(A,B). -difflength_x([_|T]-A,M,N) :- succ(M,L), difflength_x(T-A,L,N). - - -%term_codes(T,C) :- with_output_to(codes(C),write(T)). - - - - -% try these? -%setof(X,Q,XS,S1,S2) :- setof(X,phrase(Q,S1,S2),XS). -%findall(X,Q,XS,S1,S2) :- findall(X,phrase(Q,S1,S2),XS). - -with_nth_arg(K,P,T1,T2) :- - functor(T1,F,N), - functor(T2,F,N), - with_nth_arg(N,K,P,T1,T2). - -with_nth_arg(K,K,P,T1,T2) :- - arg(K,T1,C1), phrase(P,C1,C2), - arg(K,T2,C2), succ(N,K), - copy_args(N,T1,T2). - -with_nth_arg(N,K,P,T1,T2) :- - arg(N,T1,C), - arg(N,T2,C), - succ(M,N), - with_nth_arg(M,K,P,T1,T2). - -copy_args(0,_,_) :- !. -copy_args(N,T1,T2) :- - succ(M,N), arg(N,T1,X), arg(N,T2,X), - copy_args(M,T1,T2). - - -%% setof( Template:X, Phrase:phrase(S), Results:list(X), S1:S, S2:S) is nondet. -setof(X,Q,XS,S1,S2) :- setof(X,phrase(Q,S1,S2),XS). - -%% findall( Template:X, Phrase:phrase(S), Results:list(X), S1:S, S2:S) is nondet. -findall(X,Q,XS,S1,S2) :- findall(X,phrase(Q,S1,S2),XS). - - -:- meta_predicate lift(0,?,?), lift(1,?,?), lift(2,?,?). - -lift(P) --> { call(P) }. -lift(P,X) --> { call(P,X) }. -lift(P,X,Y) --> { call(P,X,Y) }. -
--- a/prolog/ops.pl Thu Jan 19 15:23:35 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ - -:- module(ops,[ - op(550,xfx,..) % range of integers - , op(550,xfx,--) % closed real interval - , op(600,xfx,--\) % half open real interval - , op(1100,xfx,:<:) % subtype declaration - , op(1100,xfx,::=) % definition - , op(1100,xfx,:=:) % type equivalence/definition - , op(1100,xfx,::) % declaration - , op(1100,xfx,<-) % element of, instance etc. - %, op(1050,yfx,¬) % restriction, eg real¬integer means fractional - , op(750,xfy,\\) % lambda abdstraction - , op(400,xfy,\) % reverse matrix division - , op(800,xfx,~) % for annotations - , op(900,fy,struct) - , op(900,fy,options) - , op(100,yfx,@) % used for signal@rate... - , op(200,yfx,++) % used for sequential composition - , op(700,xfx,in) - , op(150,yfx,`) % function application - , op(100,yfx,/) - %, op(400,xfy,>>) % monad sequencing NB: standard prolog has yfx not xfy - %, op(400,xfy,>>=) % monad bind - , op(1050,xfy,>>) % monad sequencing NB: standard prolog has yfx not xfy - , op(1050,xfy,>>=) % monad bind - , op(100,fx,'<?>') - , op(800,xfx,'</>') - , op(100,fx,?) - ]). - -/** <module> - Operator declarations - -This module consists entirely of operator declarations, as follows: -== -op(550,xfx,..). -op(550,xfx,--). -op(600,xfx,--\). -op(1100,xfx,:<:). -op(1100,xfx,::=). -op(1100,xfx,:=:). -op(1100,xfx,::). -op(1100,xfx,<-). -op(750,xfy,\\). -op(400,xfy,\). -op(800,xfx,~). -op(900,fy,maybe). -op(900,fy,struct). -op(900,fy,options). -op(100,yfx,@). -op(200,yfx,++). -op(700,xfx,in). -op(150,yfx,`). -op(100,yfx,/). -op(1050,xfy,>>). -op(1050,xfy,>>=). -op(100,fx,'<?>'). -op(800,xfx,'</>'). -op(100,fx,?). -== - -@author Samer Abdallah -*/
--- a/prolog/plml.pl Thu Jan 19 15:23:35 2012 +0000 +++ b/prolog/plml.pl Fri Jan 20 16:46:57 2012 +0000 @@ -746,8 +746,8 @@ db_tmp(I,Z,Y) :- ml_eval(I,dbtmp(Z),[loc],[Y]). db_drop(I,mat(A,B)) :- ml_exec(I,dbdrop(\loc(A,B))). -db_save_all(I,Z,L,Size) :- ml_eval(I,cellmap(@dbsave,Z),[cell(loc,Size)],[L]). -db_tmp_all(I,Z,L,Size) :- ml_eval(I,cellmap(@dbtmp,Z),[cell(loc,Size)],[L]). +db_save_all(I,Z,L,Size) :- ml_eval(I,dbcellmap(@dbsave,Z),[cell(loc,Size)],[L]). +db_tmp_all(I,Z,L,Size) :- ml_eval(I,dbcellmap(@dbtmp,Z),[cell(loc,Size)],[L]). db_drop_all(I,L,Size) :- length(Size,Dims), ml_exec(I,hide(foreach(@dbdrop,arr(Dims,L,X\\{loc(X)})))).
--- a/prolog/update Thu Jan 19 15:23:35 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ -#!/bin/sh -cp -p ~/src/sapl-2.0/{dcgu,ops,utils}.pl .
--- a/prolog/utils.pl Thu Jan 19 15:23:35 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,960 +0,0 @@ -% Some general utilities - -:- module(utils,[ - - % type testing and enumeration - natural/1 % test or enumerate natural numbers - , isfinite/1 % check number is non NaN or Inf - , int/1 % test or enumerate integers - , in/2 - - % mathematical utilities - , max/3 - , min/3 - - % list utilities - , list_idx1_member/3 % like nth1 but more useful argument order - , apply_to_nth1/4 - , measure/3 % match list lengths - , equal_length/2 % match 2 list lengths - , getopts/2 - , rep/3 % make a list of repeats of the same term - , cons/3 % list constructror - , decons/3 % list deconstructor - - % comma lists - , cl_list/2 - , cl_list_vt/2 - , cl_length/2 - , cl_length_vt/2 - , cl_member/2 - - - % term manipulation - , copy_head/2 % check terms for same head and arity - , unify_args/5 - , reinstatevars/3 - , reinstatevars/4 - - % formatting and parsing - , aphrase/2 % like phrase but makes an atom instead of a string - , aphrase/3 % like aphrase but takes code list - , print_list/1 % writes each element on a new line - , printq_list/1 % as print_list but quotes atom as necessary - , print_numbered_list/1 - - % database management - , extensible/1 % declare dynamic multifile predicate - , bt_assert/1 - , bt_retract/1 - , strict_assert/1 - , strict_retract/1 - , browse/2 % browse predicate with unknown arity - , current_state/2 - , set_state/2 - - % file system utilities - , dir/2 % directory listing - , path_atom/2 % expand paths - , expand_path/2 % expand paths - - % operating system - , open_with/2 % apply shell command to a file (SIDE EFFECTS) - , open_with/3 % apply shell command to a file with options (SIDE EFFECTS) - , shellcmd/2 % apply shell command to arguments - , open_/1 % open with 'open' command (Mac OS X). - , fmt_shellcmd/3 % format a shell command with switches and args - , hostname/1 - - % user interaction - , read_char_echo/1 % read one character and echo it immediately - , get_key/2 % read and validate keypress - , userchk/1 % unary predicate which allows user to force failure - , prompt_for_key/3 - - % ---- high order stuff ---- - - % modes of computation - , retry/1 % keep trying until success - , parallel/1 % parallel computation using threads - , bt_call/2 % Construct backtrackable operation - , on_backtracking/1 - - % iteration - , exhaust/1 % trigger all solutions to a goal (SIDE EFFECTS) - , iterate/3 % apply predicate recursively till failure - - % mapping - , for_naturals/2 % call predicate with natural numbers N down to 1 - , mapints/2 % call predicate with integers - , mapints/3 - , mapargs/2, mapargs/3, mapargs/4 - , mapargs_x/4, mapargs_x/5, mapargs_x/6 - , mapargs_xx/6 - , sfold/4 % structural fold for lists - , take/3 - , drop/3 - , drop_while/3 - , take_while/3 - - % lambda expressions - , mcall/2, mcall/3, mcall/4 - - ]). - -/** <module> General utilities - -The predicates in this module can be divided into several groups as listed -below. - ----+++ Type testing and enumeration - * natural/1 - test or enumerate natural numbers - * isfinite/1 - check number is non NaN or Inf - * int/1 - test or enumerate integers - * in/2 - ----+++ mathematical utilities - * max/3 - * min/3 - ----+++ list utilities - * list_idx1_member/3 % like nth1 but more useful argument order - * measure/3 - match list lengths - * equal_length/2 - match two list lenghts - * getopts/2 - * rep/3 - make a list of repeats of the same term - * cons/3 - make list from head and tail - * decons/3 - get head and tail from list - ----+++ term manipulation - * copy_head/2 - check terms for same head and arity - * unify_args/5 - * reinstatevars/3 - * reinstatevars/4 - ----+++ formatting and parsing - * aphrase/2 - like phrase but makes an atom instead of a string - * aphrase/3 - like aphrase but takes code list - * print_list/1 - write/1 each element, one per line - * printq_list/1 - as print_list but quotes atom as with writeq/1 - * print_numbered_list/1 - as print_list/1 but with line numbers - ----+++ database management - * extensible/1 - declare dynamic multifile predicate - * bt_assert/1 - * bt_retract/1 - * strict_assert/1 - * strict_retract/1 - * browse/2 - browse predicate with unknown arity - * current_state/2 - * set_state/2 - ----+++ file system utilities - * dir/2 - directory listing - * path_atom/2 - expand paths - * expand_path/2 - expand paths - ----+++ operating system - * open_with/2 - apply shell command to a file (SIDE EFFECTS) - * open_with/3 - apply shell command to a file with options (SIDE EFFECTS) - * shellcmd/2 - apply shell command to arguments - * open_/1 - open with 'open' command (Mac OS X). - * fmt_shellcmd/3 - format a shell command with switches and args - * hostname/1 - ----+++ user interaction - * read_char_echo/1 - read one character and echo it immediately - * get_key/2 - read and validate keypress - * userchk/1 - unary predicate which allows user to force failure - * prompt_for_key/3 - print message and get keypress from user - ----+++ High order stuff - ----++++ modes of computation - * retry/1 - keep trying until success - * parallel/1 - parallel computation using threads - * bt_call/2 - Construct backtrackable operation - , on_backtracking/1 - ----++++ iteration - * exhaust/1 - trigger all solutions to a goal (SIDE EFFECTS) - * iterate/3 - apply predicate recursively till failure - ----++++ mapping - * for_naturals/2 - call predicate with natural numbers N down to 1 - * mapints/2 - call predicate with integers - * mapints/3 - * mapargs/2, mapargs/3, mapargs/4 - * mapargs_xx/6 - * sfold/4 - structural fold for lists - * take/3 - * drop/3 - * drop_while/3 - * take_while/3 - ----++++ lambda expressions - * mcall/2, mcall/3, mcall/4 - */ - -:- use_module(library(ops)). - -:- meta_predicate - exhaust(0) - , retry(0) - , iterate(2,?,?) - , drop_while(1,?,?) - , take_while(1,?,?) - , apply_to_nth1(?,2,?,?) - , for_naturals(+,1) - , for_ints(+,+,1) - , mapints(1,?) - , mapints(2,?,?) - , mapargs(1,?) - , mapargs(2,?,?) - , mapargs(3,?,?,?) - , mapargs_x(+,+,1,?) - , mapargs_x(+,+,2,?,?) - , mapargs_x(+,+,3,?,?,?) - , mapargs_xx(2,?,?,?,?,?) - , on_backtracking(0) - , bt_call(0,0) - , bt_assert(:) - , bt_retract(:) - , strict_assert(:) - , strict_retract(:) - , extensible(:) - , aphrase(2,?) - , aphrase(2,?,?) - . - -:- multifile user:path/2. -:- multifile user:demo/1. -:- dynamic current_state/2. - - -%% extensible(+P) is det. -% declares 'extensible' predicates, ie ones that can have new clauses -% added in other files. Equivalent to dynamic(P), multifile(P). -extensible(P) :- dynamic(P), multifile(P). - - -%% natural(+N) is semidet. -%% natural(-N:natural) is multi. -% -% Means N is a natural number (includes 0). If N is -% a variable, succeeds an infinite number of times on backtracking, -% returning all natural numbers. -natural(N) :- (var(N) -> between(0,inf,N); integer(N), N>=0). - - -%% int(+N) is semidet. -%% int(-N:integer) is multi. -% -% Means N is an integer. If N is -% a variable, succeeds an infinite number of times on backtracking, -% returning all integers starting at zero and interleaving positive -% and negative values. -int(N) :- nonvar(N), integer(N). -int(N) :- var(N), (N=0; (between(1,inf,M), (N=M; N is -M))). - - -%% isfinite(+N:number) is semidet. -% -% Succeeds when N is a finite number. -isfinite(N):- catch(_ is N+0,error(_,_),fail). % !! workable hack - - -%% in(+X,Set) is semidet. -%% in(-X,Set) is nondet. -% -% Simple testing and enumration of values in some sets. -% Set can be -% * {A,B,_} -% Explicit list of values. -% * natural -% Natural numbers starting from 0. -% * integer -% Natural numbers. -% * real -% Real (floating point) numbers. -% * A..B -% Integer range from A to B inclusive. -% * A--B -% Closed interval [A,B]. -X in A--\B :- X in A--(\B). -X in \A--(\B):- !, ch(A<X), ch(X<B). -X in \A--B :- !, ch(A<X), ch(X=<B). -X in A--(\B) :- !, ch(A=<X), ch(X<B). -X in A--B :- !, ch(A=<X), ch(X=<B). -X in A..B :- integer(A), integer(B), between(A,B,X). -X in {CList} :- member_clist(X,CList). -X in natural :- natural(X). % enumerate! -X in integer :- int(X). % enumerates! -X in real :- number(X). % same as X :: real - - -ch(_ =<inf) :- !. -ch(inf=< _ ) :- !, fail. -ch(-inf=< _) :- !. -ch(_ =<(-inf)) :- !, fail. -ch(A=<B) :- !, A=<B. - -ch(inf<_ ) :- !, fail. -ch(_ <inf) :- !. -ch(_ <(-inf)) :- !, fail. -ch(-inf<_ ) :- !. -ch(A<B) :- !, A<B. - - - -%% exhaust(:Goal) is det. -% -% Repeat Goal until failure, then succeed. -exhaust(Q) :- call(Q), fail; true. - -%% iterate(+P:pred(A,A), X:A, Y:A) is semidet. -% apply P recursively to X until failure, then return final value Y. -iterate(P,X,Y) :- call(P,X,Z) -> iterate(P,Z,Y); Y=X. - -%% sfold(Functor,Initial,L:list,Final) is semidet. -% *Structural* fold applied to a term, -% rather than a relational fold using a predicate name. -sfold(_,E,[],E). -sfold(O,E,[X|XX],R) :- R=..[O,X,YY], sfold(O,E,XX,YY). - - -%% dir( +Pattern, -File) is nondet. -% -% Directory listing for directory matching Pattern. File -% names are returned one by one on backtracking. -dir(Pattern,File) :- - expand_file_name(Pattern,List), - member(File,List). - - -%% path_atom( +Spec:path_expr, -Path:atom) is nondet. -% -% Expand a 'path expression' into a flat path (an atom). -% A path expression is defined by: -% == -% path_expr ---> atom % literal path component name -% ; path_expr/atom % child of path_expr -% ; path_macro % a previously defined abbr for a path. -% == -% A path_macro is defined using path/2. - -path_atom(P,C) :- path(P,C), atom(C). - -path_atom(PA/B,C) :- - once((nonvar(C); nonvar(B); nonvar(PA))), - path_atom(PA,A), - concat3atoms(A,'/',B,C). - - -path_atom(Path,Atom) :- path(Path, Def), \+atom(Def), path_atom(Def,Atom). -path_atom(Path,Atom) :- - nonvar(Path), - \+path(Path,_), - Path\=_/_, - Atom=Path. - -concat3atoms(A,B,C,ABC) :- - nonvar(A), nonvar(B), nonvar(C), !, concat_atom([A,B,C],ABC). - -concat3atoms(_,_,_,ABC) :- var(ABC), !, fail. -concat3atoms(A,B,C,ABC) :- nonvar(C), !, atom_concat(AB,C,ABC), atom_concat(A,B,AB). -concat3atoms(A,B,C,ABC) :- nonvar(A), !, atom_concat(A,BC,ABC), atom_concat(B,C,BC). -concat3atoms(A,B,C,ABC) :- - maplist(atom_codes,[B,ABC],[BX,ABCX]), - append(ABX,CX,ABCX), - append(AX,BX,ABX), - maplist(atom_codes,[A,C],[AX,CX]). - -%% expand_path( +P:path_expr, -FP:atom) is semidet. -% -% Expand path_exp including wildcards to fully qualified path -expand_path(P,FP) :- path_atom(P,PP), expand_file_name(PP,[FP]). - - -%% open_with( +Program:atom, +Thing:path_expr, +Options:list) is semidet. -%% open_with( +Program:atom, +Thing:path_expr) is semidet. -% -% The only option is bg, which adds "&" to make command execute in background. -open_with(Q,P) :- open_with(Q,P,[]). -open_with(Q,P,Opts) :- - expand_path(P,FP), - (member(bg,Opts) -> OO=' &'; OO=''), - sformat(S,'~w ~q~w',[Q,FP,OO]), - shell(S). - -%% open_( +Thing:path_expr) is semidet. -% Equivalent to open_with(open,Thing). -open_(P) :- open_with(open,P). - -%% shellcmd( +Head:atom, +Args:list(atom)) is det. -% -% Execute a shell command on a given list of arguments -shellcmd(Head,Args) :- - concat_atom([Head|Args],' ',Cmd), - shell(Cmd,_Status). - -%% fmt_shellcmd( +Prog:atom, +Args:list(shellarg), -Cmd) is det. -% make a shell command string. -fmt_shellcmd(Prog,Args,Cmd) :- - phrase(utils:shellcmd(l_(Args)),FArgs), - concat_atom([Prog|FArgs],' ',Cmd). - -shellcmd(l_([])) --> !, []. -shellcmd(l_([H|T])) --> !, shellcmd(H), shellcmd(l_(T)). -shellcmd(s(N,V)) --> !, shellcmd(s(N)), shellcmd(V). -shellcmd(q(X)) --> !, { concat_atom(['"',X,'"'],A) }, [A]. -shellcmd(s(N)) --> !, { - (atom_codes(N,[_]) -> F='-' ; F='--'), - atom_concat(F,N,A) }, [A]. -shellcmd(l(X)) --> [X]. - - - -%% read_char_echo( -C:atom) is det. -% -% Read a single character from the current input, -% echo it to the output. -read_char_echo(C) :- - get_single_char(Code), - put_code(Code), flush_output, - char_code(C,Code). - - - -%% set_state( +Key, +Value) is det. -% -% Maintains a mutable global set of Key-Value pairs, sets the value -% associated with Key to Value. -set_state(Flag,Value) :- - ground(Flag), - retractall(current_state(Flag,_)), - assert(current_state(Flag,Value)). - - -%% current_state( -Key, -Value) is nondet. -%% current_state( +Key, -Value) is semidet. -% -% Lookup the value associated with Key, or enumerate all the -% key value pairs. - - - -%% parallel( +List:list(query)) is semidet. -% -% Use this by giving a list of queries of the form -% [Vars2:Goal, Vars2:Goal2, ...] -% where Vars is the term that each thread must return -% when it has finished computing its Goal. The -% parallel predicate finishes when all the threads -% have finished, and should result in all the Vars -% being bound appropriately. - -parallel(Queries) :- - maplist(async,Queries,Collecters), - maplist(call,Collecters). - -% these are used to initiate and wait for each -% computation thread. -async_collect(Id,X:_) :- thread_join(Id,exited(X)). -async(X:Goal,utils:async_collect(Id,X:_)) :- - thread_create((Goal,thread_exit(X)),Id,[]). - -%% browse( +PredSpec, -Goal) is nondet. -% -% PredSpec is a term like (PredicateName/Arity). Goal -% is unified with solutions of PredicateName/Arity. -browse(P/A,Goal) :- - current_predicate(P/A), - length(L,A), - Goal=..[P|L], - call(Goal). - - - -%% aphrase(P:phrase(code), -A:atom, +S:list(code)) is nondet. -%% aphrase(P:phrase(code), +A:atom, -S:list(code)) is nondet. -%% aphrase(P:phrase(code), -A:atom, -S:list(code)) is nondet. -%% aphrase(P:phrase(code), -A:atom) is nondet. -% -% Generate or parse an atom using given DCG phrase P. -% aphrase(P,A) is equivalent to aphrase(P,A,_). -aphrase(X,A) :- aphrase(X,A,_). -aphrase(X,A,S) :- - ( ground(A) - -> atom_codes(A,S), phrase(X,S) - ; phrase(X,S), atom_codes(A,S)). - - -%% print_list( +L:list) is det. -% -% Print a list, one item per line. -print_list([]) :- writeln('~'), nl. -print_list([H|T]) :- print(H), nl, print_list(T). - -%% printq_list( +L:list) is det. -% -% Print a list, one item per line, as with writeq/1. -printq_list([]) :- writeln('~'), nl. -printq_list([H|T]) :- writeq(H), nl, printq_list(T). - -%% print_numbered_list( +L:list) is det. -% -% Print a list with numbered lines. -print_numbered_list(L) :- - length(L,Max), - number_codes(Max,MC), - length(MC,Width), - print_num_list(Width,1,L). - -print_num_list(_,_,[]) :- nl. -print_num_list(Width,N,[H|T]) :- succ(N,M), - copy_term(H,H1), - numbervars(H1,0,_), - number_codes(N,NC), " "=[Pad], - padleft(Pad,Width,NC,PNC), - format('~s. ~q\n',[PNC,H1]), - print_num_list(Width,M,T). - -padleft(_,W,In,In) :- length(In,W). -padleft(P,W,In,[P|Out]) :- succ(V,W), padleft(P,V,In,Out). - - - - -%% get_key( +Valid:list(char), -C:char) is det. -% -% Get and validate a key press from the user. The character -% must be one of the ones listed in Valid, otherwise, an -% error message is printed and the user prompted again. -get_key(Valid,C) :- - read_char_echo(D), nl, - ( member(D,Valid) -> C=D - ; D='\n' -> get_key(Valid,C) % this improves interaction with acme - ; format('Unknown command "~q"; valid keys are ~q.\n', [D,Valid]), - write('Command? '), - get_key(Valid,C)). - - -%% userchk(T) is semidet. -% -% Write T and ask this user if it is ok. User presses y or n. -% userchk succeeds if if the keypress was y and fails if it was n. -userchk(T) :- prompt_for_key(T,[y,n],y). - - -%% prompt_for_key( +Msg:atom, +Keys:list(char), -Key:char) is semidet. -% -% Prompt user for a keypress. Prompt message is Msg, and valid keys are -% listed in Keys. -prompt_for_key(Msg,Keys,Key) :- format('~p ~q? ',[Msg,Keys]), get_key(Keys,Key). - -% ------------------- TERM MANIPULATION ------------------------------ - - -%% copy_head(+T1,-T2) is det. -%% copy_head(+T1,+T2) is semidet. -% -% true if T1 and T2 have the same head and arity -copy_head(T1,T2) :- functor(T1,N,A), functor(T2,N,A). - - - -%% reinstatevars( F:atom, V:list, Eh, What) is nondet. -%% reinstatevars( V:list, Eh, What) is nondet. -% -% Reverse of numbervars. Each '$VAR'(N) subterm of X is replaced -% with the Nth element of V, which can be uninstantiated on entry -% reinstatevars/4 uses an arbitrary functor F instead of $VAR. - -reinstatevars(V,'$VAR'(N),Y) :- !, nth0(N,V,Y). -reinstatevars(_,X,Y) :- atomic(X), !, Y=X. -reinstatevars(V,X,Y) :- mapargs(reinstatevars(V),X,Y). - -reinstatevars(F,V,T,Y) :- functor(T,F,1), !, arg(1,T,N), nth0(N,V,Y). -reinstatevars(_,_,X,Y) :- atomic(X), !, Y=X. -reinstatevars(F,V,X,Y) :- mapargs(reinstatevars(F,V),X,Y). - - -%% unify_args( Src, SrcIndex, Dest, DestIndex, Num) is det. -% -% this unifies N consecutive arguments of Src and Dest starting -% from SI and DI in each term respectively -unify_args(_,_,_,_,0). -unify_args(Src,SI,Dest,DI,N) :- - arg(SI,Src,X), arg(DI,Dest,X), !, - succ(SI,SI2), succ(DI,DI2), succ(N2,N), - unify_args(Src,SI2,Dest,DI2,N2). - - -% ---------------------- LIST UTILITIES ----------------------------- - - -%member_clist(_,Z) :- var(Z), !, fail. -member_clist(A,A) :- A\=(_,_). -member_clist(A,(A,_)). -member_clist(A,(_,B)) :- member_clist(A,B). - - - -%% measure(Ruler,In,Out) is det. -% true if Out is the same length as Ruler but matches In as far as possible -measure([],_I,[]). -measure([_|R],[],[_|O]) :- measure(R,[],O). -measure([_|R],[X|I],[X|O]) :- measure(R,I,O). - -%% equal_length( ?In, ?Out) is nondet. -% equal_length( +L1:list, -L2:list) is det. -% equal_length( -L1:list, +L2:list) is det. -% -% True if L1 and L2 are the same length. -equal_length([],[]). -equal_length([_|T1],[_|T2]) :- equal_length(T1,T2). - -%split_at(0,T,I-I,T). -%split_at(N,[H|T],[H|I1]-Z,T1) :- succ(M,N), split_at(M,T,I1-Z,T1). - -%split_at2(0,T,I-I,T). -%split_at2(N,[H|T],[H|I1]-Z,T1) :- split_at2(M,T,I1-Z,T1), succ(M,N). - -%% max(+X:number, +Y:number, -Z:number) is det. -% -% Unify Z with the larger of X and Y. Legal values are -% any numerical value or inf or -inf. -max(_,inf,inf) :- !. -max(inf,_,inf) :- !. -max(X,-inf,X) :- !. -max(-inf,X,X) :- !. -max(X,Y,Z) :- X<Y -> Z=Y; Z=X. - -%% max(+X:number, +Y:number, -Z:number) is det. -% -% Unify Z with the larger of X and Y. Legal values are -% any numerical value or inf or -inf. -min(_,-inf,-inf) :- !. -min(-inf,_,-inf) :- !. -min(X,inf,X) :- !. -min(inf,X,X) :- !. -min(X,Y,Z) :- X<Y -> Z=X; Z=Y. - -%% list_idx1_member( +L:list(A), +N:natural, ?X:A) is semidet. -%% list_idx1_member( ?L:list(A), ?N:natural, ?X:A) is nondet. -% -% Equivalent to nth1(N,L,X). -list_idx1_member(L,I,X) :- nth1(I,L,X). - - -%% getopts( +Opts:list(option), ?Spec:list(optspec)) is det. -% -% Get value from option list. -% == -% option(A) ---> term(A). -% optspec ---> option(A)/A. -% == -getopts(OptsIn,Spec) :- maplist(getopt(OptsIn),Spec). -getopt(OptsIn,Option/Default) :- option(Option,OptsIn,Default). - -%% cons( ?Head:A, ?Tail:list(A), ?List:list(A)) is det. -% -% List constructor. -cons(H,T,[H|T]). - -%% decons( ?Head:A, ?List:list(A), ?Tail:list(A)) is det. -% -% List deconstructor. -decons(H,[H|T],T). - -% ---------------------- MAPPING, HIGH ORDER STUFF --------------------- - -%% for_naturals(+N:natural, P:pred(natural)) is nondet. -% apply predicate to each natural number from 1 to N (backwards) -for_naturals(0,_). -for_naturals(N,P) :- succ(M,N), call(P,N), for_naturals(M,P). - -%% mapints( +P:pred(integer,A), +R:intrange, -X:list) is nondet. -%% mapints( +P:pred(integer), +R:intrange) is nondet. -% -% Mapping predicates over lists of integers. Range is like M..N. -% mapints/3 maps 2 argument predicate over implicit list of -% integers M..N and explicit list of values X. -mapints(_,M..N) :- N<M, !. -mapints(P,M..N) :- call(P,M), plus(M,1,L), mapints(P,L..N). - -mapints(_,M..N,[]) :- N<M, !. -mapints(P,M..N,[X|T]) :- call(P,M,X), plus(M,1,L), mapints(P,L..N,T). - -%% rep( +N:natural, ?X:A, -L:list(A)) is det. -%% rep( -N:natural, ?X:A, -L:list(A)) is multi. -% Make a list consisting of N repeats of the same term. If called -% with N unbount, creates progressively longer and longer lists -% on backtracking. -rep(0,_,[]). -rep(N,A,[A|X]) :- - ( nonvar(N) - -> succ(M,N), rep(M,A,X) - ; rep(M,A,X), succ(M,N) - ). - -%% mapargs( P:pred(A,B,C), T1:tuple(F,A), T2:tuple(F,B), T3:tuple(F,C)) is nondet. -%% mapargs( P:pred(A,B), T1:tuple(F,A), T2:tuple(F,B)) is nondet. -%% mapargs( P:pred(A), T1:term) is nondet. -% -% Map predicate over to args of a term preserving head. -% A tuple(F,A) is a term with head functor F and any number of arguments -% of type A, ie -% == -% tuple(F,A) ---> F ; F(A) ; F(A,A) ; F(A,A,A) ; .. . -% == - -mapargs(P,T1) :- - functor(T1,_,N), - mapargs_x(1,N,P,T1). - -mapargs(P,T1,T2) :- - ( nonvar(T1) - -> functor(T1,F,N), functor(T2,F,N) - ; functor(T2,F,N), functor(T1,F,N)), - mapargs_x(1,N,P,T1,T2). - -mapargs(P,T1,T2,T3) :- - functor(T1,F,N), - functor(T2,F,N), - functor(T3,F,N), - mapargs_x(1,N,P,T1,T2,T3). - -mapargs_x(I,N,P,T1) :- - ( I>N -> true - ; arg(I,T1,X1), - call(P,X1), - succ(I,J), mapargs_x(J,N,P,T1)). - -mapargs_x(I,N,P,T1,T2) :- - ( I>N -> true - ; arg(I,T1,X1), - arg(I,T2,X2), - call(P,X1,X2), - succ(I,J), mapargs_x(J,N,P,T1,T2)). - -mapargs_x(I,N,P,T1,T2,T3) :- - ( I>N -> true - ; arg(I,T1,X1), - arg(I,T2,X2), - arg(I,T3,X3), - call(P,X1,X2,X3), - succ(I,J), mapargs_x(J,N,P,T1,T2,T3)). - -%% drop( +N:natural, +In:list(A), -Out:list(A)) is det. -drop(0,T,T). -drop(N,[_|T],V) :- succ(M,N), drop(M,T,V). - - -%% take( +N:natural, +In:list(A), -Out:list(A)) is det. -take(N,T,X) :- length(X,N), append(X,_,T). - - -%% drop_while( +P:pred(A), +In:list(A), -Out:list(A)) is det. -% -% Remove all elements from head of In that are accepted by P -% and return the remained in Out. -drop_while(P,[X|T],V) :- call(P,X) -> drop_while(P,T,V); V=[X|T]. - - -%% take_while( +P:pred(A), +In:list(A), -Out:list(A)) is det. -% -% Remove all elements from head of In that are accepted by P -% and return them in Out. -take_while(P,[X|T],O) :- call(P,X) -> O=[X|V], take_while(P,T,V); O=[]. - - - -%% retry( :Goal) is det. -% -% Keep retrying Goal until it succeeds. Only makes sense if Goal -% has side effects. Might be nonterminating. -retry(G) :- once((repeat,G)). - -%% apply_to_nth1( N:natural, Op:pred(A,A), +In:list(A), +Out:list(A)) is nondet. -% -% Apply predicate Op to the N th element of list In and unify Out with the result. -%apply_to_nth1(N,Op,Old,Init) :- -% ( nonvar(N) -% -> succ(M,N), split_at(M,Old,Init-[Y|Tail],[X|Tail]) -% ; split_at2(M,Old,Init-[Y|Tail],[X|Tail]), succ(M,N) -% ), -% call(Op,X,Y). - -apply_to_nth1(1,P,[X|XX],[Y|XX]) :- call(P,X,Y). -apply_to_nth1(N,P,[X|X1],[X|Y1]) :- nonvar(N), !, N>1, succ(M,N), apply_to_nth1(M,P,X1,Y1). -apply_to_nth1(N,P,[X|X1],[X|Y1]) :- var(N), !, apply_to_nth1(M,P,X1,Y1), succ(M,N). - - -%% mapargs_xx( +P:pred(A,B), +Src:term(_,A), +SrcIndex:natural, +Dest:term(_,B), +DestIndex:natural, +N:natural) is nondet. -% -% Maps predicate P over N consecutive arguments of Src and Dest. Starts -% at SrcIndex th argument of Src and DestIndex th argument of Dest. -mapargs_xx(_,_,_,_,_,0). -mapargs_xx(Pred,Src,SI,Dest,DI,N) :- - arg(SI,Src,SX), arg(DI,Dest,DX), call(Pred,SX,DX), !, - succ(SI,SI2), succ(DI,DI2), succ(N2,N), - mapargs_xx(Pred,Src,SI2,Dest,DI2,N2). - - -%% mcall(P:pred(A), X:A) is nondet. -%% mcall(P:pred(A,B), X:A, Y:B) is nondet. -%% mcall(P:pred(A,B,C), X:A, Y:B, Z:C) is nondet. -%% mcall(P:pred(A,B,C,D), X:A, Y:B, Z:C, W:D) is nondet. -% -% Like call/N but P can additionally be a lambda expression in one of several -% forms: -% * Tuple :- Body -% If functor(Tuple,\,N), Body is executed after unifying tuple arguments -% with arguments to mcall, eg =mcall(\(X):-member(X,[a,b,c]),Y)= is equivalent -% to member(Y,[a,b,c]), or =mcall(\(X,Y):-nth1(X,[a,b,c],Y),2,c)=. -% * Tuple -% Equivalent to Tuple:-true. - -mcall(P,A) :- mc(P,\(A),Q), Q. -mcall(P,A,B) :- mc(P,\(A,B),Q), Q. -mcall(P,A,B,C) :- mc(P,\(A,B,C),Q), Q. -mcall(P,A,B,C,D) :- mc(P,\(A,B,C,D),Q), Q. - -mc(Tuple:-Body,Params,Goal) :- !, copy_term(Tuple/Body,Params/Goal). -mc(Tuple,Params,true) :- functor(Tuple,\,_), !, copy_term(Tuple,Params). -mc(P,Params,apply(P,Args)) :- Params=..[\|Args]. - - -%% on_backtracking( :Goal) is det. -% -% The first time this is called, it succeeds and does nothing. -% On backtracking, Goal is called and then a failure is generated. - -on_backtracking(_). -on_backtracking(P) :- P, !, fail. - - -%% bt_call( :Do, :Undo) is nondet. -% -% Creates a backtrackable operation from a non-backtrackable Do -% operation and a corresponding operation to undo it. Do can -% be non-deterministic, in which case bt_call(Do,Undo) will also -% have multiple solutions. Undo is called inside once/1. -% -% bt_call/2 is implemented both as a predicate and as a goal -% expansion (see goal_expansion/2). -bt_call(Do,Undo) :- Do, (true; once(Undo), fail). - -user:goal_expansion( bt_call(Do,Undo), (Do, (true; once(Undo), fail))). - - - -/* Might include these at some point - -% apply lambda term to another term -app(X\\F,Y,G) :- !, copy_term(X\\F,Y\\G). -app(T,A,Z) :- addargs(T,[A],Z). -app(T,A,B,Z) :- addargs(T,[A,B],Z). -app(T,A,B,C,Z) :- addargs(T,[A,B,C],Z). - -applist(F,N,A,Z) :- length(Z,N), maplist(app(F),A,Z). -applist(F,N,A,B,Z) :- length(Z,N), maplist(app(F),A,B,Z). -applist(F,N,A,B,C,Z) :- length(Z,N), maplist(app(F),A,B,C,Z). - -*/ - - -% ------------------ DATABASE ------------------------------ - -%% bt_assert(Clause) is det. -% Backtrackable assert. -bt_assert(H) :- bt_call(assert(H),retract(H)). - -%% bt_retract(Clause) is det. -% Backtrackable retract. -bt_retract(H) :- bt_call(retract(H), assert(H)). - -%% strict_assert(Fact) is semidet. -% -% Asserts fact only if it is not already true. Fails -% if fact is already provable. Retracts fact on backtracking. -strict_assert(H) :- \+call(H), bt_call(assert(H),retract(H)). - - -%% strict_retract(Fact) is semidet. -% -% Retracts fact only if it is currently in the database. Fails -% if fact is not provable. Reasserts fact on backtracking. -strict_retract(H) :- call(H), bt_call(retract(H), assert(H)). - - -% when loaded, this sets the hostname/1 predicate. -:- dynamic hostname/1. - -%% hostname( -A:atom) is det. -% -% Unifies A with the computer's hostname. This is set when the -% module is loaded by calling the system command 'hostname -s'. - -% init_hostname is det - read hostname from UNIX command hostname. -init_hostname :- - setup_call_cleanup( - open(pipe('hostname -s'),read,SID), - (read_line_to_codes(SID,C), atom_codes(H,C), retractall(hostname(_)), assert(hostname(H))), - close(SID)). - -:- ( hostname(H) - -> format('% hostname already set to ~w\n',[H]) - ; init_hostname, hostname(H), format('% hostname set to ~w\n',[H]) - ). - -% Comma lists -% ie, lists built up using (,) as a pairing functor -% Note, these functor lists do NOT have a nil element - the -% last item in the list is the 2nd argument to the final -% functor term, which can therefore be a term headed by any -% other functor. Eg: -% (1,(2,3)) <-> [1,2,3] -% (1,(2,(3+4)) <-> [1,2,(3+4)] - -%% cl_list( +CL:clist(A), -L:list(A)) is det. -%% cl_list( -CL:clist(A), +L:list(A)) is det. -% -% Convert between comma lists and ordinary lists -cl_list((A,B),[A|BL]) :- cl_list(B,BL). -cl_list(A,[A]) :- A\=(_,_). - -%% cl_length( +L:clist, -N:natural) is det. -%% cl_length( -L:clist, +N:natural) is det. -% -% Length of a comma-list. -cl_length((_,B),N) :- cl_length(B,M), succ(M,N). -cl_length(X,1) :- X\=(_,_). - - -%% cl_list_vt( +CL:clist(A), -L:list(A)) is det. -%% cl_list_vt( -CL:clist(A), +L:list(A)) is det. -% -% Convert between comma lists (with open tails) and ordinary lists. -cl_list_vt(FL,[FL]) :- var(FL), !. -cl_list_vt(FL,[A|BL]) :- FL = (A,B), cl_list_vt(B,BL). -cl_list_vt(A,[A]) :- A\=(_,_). - - -%% cl_length_vt( +L:clist, -N:natural) is det. -%% cl_length_vt( -L:clist, +N:natural) is det. -% -% Length of a comma-list with possible variable tail. -% This version handles lists where the last element is variable (counts as 1) -cl_length_vt(FL,1) :- var(FL), !. -cl_length_vt(FL,N) :- FL=(_,B), cl_length_vt(B,M), succ(M,N). -cl_length_vt(FL,1) :- FL\=(_,_). - -%% cl_member(-X, +L:clist) is nondet. -% List membership for comma lists. -cl_member(X,(X,_)). -cl_member(X,(_,T)) :- cl_member(X,T). -cl_member(X,X) :- X\=(_,_). -