1/* Part of dcgutils 2 Copyright 2012-2015 Samer Abdallah (Queen Mary University of London; UCL) 3 4 This program is free software; you can redistribute it and/or 5 modify it under the terms of the GNU Lesser General Public License 6 as published by the Free Software Foundation; either version 2 7 of the License, or (at your option) any later version. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 GNU Lesser General Public License for more details. 13 14 You should have received a copy of the GNU Lesser General Public 15 License along with this library; if not, write to the Free Software 16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17*/ 18 19:- module(dcg_core, [ 20 nop/2 21 22 % state handling 23 , trans//2 24 , set//1, get//1, set_with//1 25 , with//2, iso//1 26 27 % control 28 , once//1 29 , repeat//0 30 , fail//0 31 , (\+)//1 32 , forall//2 33 , freeze//2 34 35 % combinators 36 , (>>)//2 37 , (//)//2 38 , maybe//1 39 , opt//1 40 , if//3, if//2 41 , do_then_call//3 42 , do_then_call//4 43 , do_then_call//5 44 , lift//1 45 , lift//2 46 , lift//3 47 48 % repetition 49 , until//2 50 , exhaust//1 51 , rep//2 52 , rep_with_sep//3 53 , rep_nocopy//2 54 , iterate//3 55 , parmap//2, parmap//3, parmap//4, parmap//5, parmap//6 56 , seqmap//2, seqmap//3, seqmap//4, seqmap//5, seqmap//6 57 , seqmap_n//3, seqmap_n//4, seqmap_n//5 58 , seqmap_with_sep//3 59 , seqmap_with_sep//4 60 , seqmap_with_sep//5 61 , seqmap_ints//3 62 , seqmap_args//4 63 , seqmap_args//5 64 , seqmap_args//6 65 66 % aggregation 67 , findall//3 68 , setof//3 69 70 % sequencing primitives 71 , out//1 72 , list//1 73 % , cons//1 74]).
115:- meta_predicate
116 if( , , , , )
117 , if( , , , )
118 , maybe( , , )
119 , opt( , , )
120 , once( , , )
121 , repeat( , )
122 , \+( , , )
123 , forall( , , , )
124 , freeze( , , , )
125 , >>( , , , )
126 , //( , , , )
127
128 , rep( , , , )
129 , rep_with_sep( , , , , )
130 , rep_nocopy( , , , )
131 , exhaust( , , )
132 , with( , , , )
133 , iso( , , )
134 , set_with( , , )
135 , iterate( , , , , )
136 , findall( , , , , )
137 , setof( , , , , )
138 , parmap( , , , )
139 , parmap( , , , , )
140 , parmap( , , , , , )
141 , parmap( , , , , , , )
142 , parmap( , , , , , , , )
143 , seqmap( , , , )
144 , seqmap( , , , , )
145 , seqmap( , , , , , )
146 , seqmap( , , , , , , )
147 , seqmap( , , , , , , , )
148 , seqmap_n( , , , , )
149 , seqmap_n( , , , , , )
150 , seqmap_n( , , , , , , )
151 , seqmap_ints( , , , , )
152 , seqmap_with_sep( , , , , )
153 , seqmap_with_sep( , , , , , )
154 , seqmap_with_sep( , , , , , , )
155 , seqmap_args( , , , , , )
156 , seqmap_args( , , , , , , )
157 , seqmap_args( , , , , , , , )
158 , do_then_call( , , , , )
159 , do_then_call( , , , , , )
160 , do_then_call( , , , , , , )
161 , until( , , , )
162 , lift( , , )
163 , lift( , , , )
164 , lift( , , , , )
.
171nop(X,X).
176trans(X,Y,X,Y).
180set(S,_,S).
184get(S,S,S).
pred( -S:A)
, ie it should set S to the new desired
state, which is installed in the DCG state.
191set_with(G,_,S) :- call(G,S).
198with(S,G) --> {call_dcg(G,S,_)}.
205iso(G,S,S) :- call_dcg(G,S,_). 206% iso(G) --> get(S), {call_dcg(G,S,_)}.
210once(G,A,B) :- once(call_dcg(G,A,B)).
214repeat(A,A) :- repeat.
218fail(_,_) :- fail.
222\+(G,A,B) :- \+call_dcg(G,A,B).
227forall(P,Q) --> \+ (call_dcg(P), \+call_dcg(Q)).
231freeze(Var,Goal,S1,S2) :- freeze(Var,call_dcg(Goal,S1,S2)).
236A >> B --> call_dcg(A), call_dcg(B).
Phrase // list(Terms)
.
phrase P, eg.
?- phrase(paren(arb)//list(C),"(hello)world",_) C = "(hello)". true
250//(P1,P2,S1,S2) :- call_dcg(P1,S1,S2), call_dcg(P2,S1,S2).
256maybe(P) --> call_dcg(P) -> []; [].
260opt(P) --> call_dcg(P); [].
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.268if(A,B,C) --> {call(A)} -> call_dcg(B); call_dcg(C). % used to have nonvar(A) 269if(A,B) --> {call(A)} -> call_dcg(B); []. 270 271 272% do_then_call( +S:phrase, +P:phrase(A), X:A)// is nondet. 273% do_then_call( +S:phrase, +P:phrase(A,B), X:A, Y:B)// is nondet. 274% do_then_call( +S:phrase, +P:phrase(A,B,C), X:A, Y:B, Z:C)// is nondet. 275% 276% Call phrase S, then call phrase P with arguments A, B, C etc. 277do_then_call(S,P,A) --> call_dcg(S), call(P,A). 278do_then_call(S,P,A,B) --> call_dcg(S), call(P,A,B). 279do_then_call(S,P,A,B,C) --> call_dcg(S), call(P,A,B,C). 280 281 282lift(P) --> { call(P) }. 283lift(P,X) --> { call(P,X) }. 284lift(P,X,Y) --> { call(P,X,Y) }.
291exhaust(G) --> call_dcg(G) -> exhaust(G); [].
300until( Pred, Op) -->
301 {copy_term(Pred/Op,Pred1/Op1)},
302 call(Op1),
303 ( {call(Pred1)}
304 -> {Pred/Op=Pred1/Op1}
305 ; until(Pred, Op)
306 ).
315iterate(_,A,A) --> []. 316iterate(F,A1,A3) --> call(F,A1,A2), iterate(F,A2,A3).
327rep(N,G,S1,S2) :-
328 ( var(N)
329 -> rep_var(N,G,S1,S2)
330 ; rep_nonvar(N,G,S1,S2)
331 ).
338rep_with_sep(Q,N,G) --> 339 {copy_term(G,G1)}, 340 ( {var(N)} 341 -> call_dcg(G1), rep_var(M,Q>>G), {succ(M,N)} 342 ; call_dcg(G1), {succ(M,N)}, rep_nonvar(M,Q>>G) 343 ). 344 345rep_var(0,_,S,S). 346rep_var(N,G,S1,S3) :- 347 copy_term(G,G1), call_dcg(G1,S1,S2), 348 rep_var(M,G,S2,S3), succ(M,N). 349 350rep_nonvar(0,_,S,S) :- !. 351rep_nonvar(N,G,S1,S3) :- 352 copy_term(G,G1), call_dcg(G1,S1,S2), 353 succ(M,N), rep_nonvar(M,G,S2,S3).
361rep_nocopy(0,_) --> !. 362rep_nocopy(N,P) --> call(P), {succ(M,N)}, rep_nocopy(M,P).
seqmap//N is very powerful - it is like foldl
and mapaccum
in functional
languages, but with the added flexibility of bidirectional Prolog variables.
381seqmap(_,[]) --> []. 382seqmap(P,[A|AX]) --> call(P,A), seqmap(P,AX). 383seqmap(_,[],[]) --> []. 384seqmap(P,[A|AX],[B|BX]) --> call(P,A,B), seqmap(P,AX,BX). 385seqmap(_,[],[],[]) --> []. 386seqmap(P,[A|AX],[B|BX],[C|CX]) --> call(P,A,B,C), seqmap(P,AX,BX,CX). 387seqmap(_,[],[],[],[]) --> []. 388seqmap(P,[A|AX],[B|BX],[C|CX],[D|DX]) --> call(P,A,B,C,D), seqmap(P,AX,BX,CX,DX). 389seqmap(_,[],[],[],[],[]) --> []. 390seqmap(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). 391 392true(_,_). 393parmap(_,[]) --> true. 394parmap(P,[A|AX]) --> call(P,A) // parmap(P,AX). 395parmap(_,[],[]) --> true. 396parmap(P,[A|AX],[B|BX]) --> call(P,A,B) // parmap(P,AX,BX). 397parmap(_,[],[],[]) --> true. 398parmap(P,[A|AX],[B|BX],[C|CX]) --> call(P,A,B,C) // parmap(P,AX,BX,CX). 399parmap(_,[],[],[],[]) --> true. 400parmap(P,[A|AX],[B|BX],[C|CX],[D|DX]) --> call(P,A,B,C,D) // parmap(P,AX,BX,CX,DX). 401parmap(_,[],[],[],[],[]) --> true. 402parmap(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).
410seqmap_n(0,_,[]) --> []. 411seqmap_n(N,P,[A|AX]) --> {succ(M,N)}, call(P,A), seqmap_n(M,P,AX). 412seqmap_n(0,_,[],[]) --> []. 413seqmap_n(N,P,[A|AX],[B|BX]) --> {succ(M,N)}, call(P,A,B), seqmap_n(M,P,AX,BX). 414seqmap_n(0,_,[],[],[]) --> []. 415seqmap_n(N,P,[A|AX],[B|BX],[C|CX]) --> {succ(M,N)}, call(P,A,B,C), seqmap_n(M,P,AX,BX,CX).
427seqmap_with_sep(S,P,[A|AX]) --> call(P,A), seqmap(do_then_call(S,P),AX). 428seqmap_with_sep(S,P,[A|AX],[B|BX]) --> call(P,A,B), seqmap(do_then_call(S,P),AX,BX). 429seqmap_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(P)
applied to the list of integers from I to J inclusive.
437seqmap_ints(P,L,N) -->
438 ( {L>N} -> []
439 ; {M is L+1}, call(P,L), seqmap_ints(P,M,N)
440 ).
452seqmap_args(P,L,N,A) --> 453 ( {L>N} -> [] 454 ; {succ(L,M), arg(L,A,AA)}, 455 call(P,AA), seqmap_args(P,M,N,A) 456 ). 457 458seqmap_args(P,L,N,A,B) --> 459 ( {L>N} -> [] 460 ; {succ(L,M), arg(L,A,AA), arg(L,B,BB)}, 461 call(P,AA,BB), seqmap_args(P,M,N,A,B) 462 ). 463 464seqmap_args(P,L,N,A,B,C) --> 465 ( {L>N} -> [] 466 ; {succ(L,M), arg(L,A,AA), arg(L,B,BB), arg(L,C,CC)}, 467 call(P,AA,BB,CC), seqmap_args(P,M,N,A,B,C) 468 ).
473setof(X,Q,XS,S1,S2) :- setof(X,call_dcg(Q,S1,S2),XS).
476findall(X,Q,XS,S1,S2) :- findall(X,call_dcg(Q,S1,S2),XS). 477 478 479%%% ------------------------------------------------------------------ 480%%% These are for sequence building DCGs. 481%%% ------------------------------------------------------------------
488out(L,[L|L0],L0).
493list(L,S1,S2) :- append(L,S2,S1).
496cons(H,T,[H|T]) :- throw(deprecated(cons/3))
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 theS
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)
, then P is a valid DCG phrase when the DCG state is of typeS
, i.e.phrase(P,S1,S2)
is valid Prolog goal when S1 and S2 are of typeS
. N.B. the typephrase(S)
is almost but not quite equivalent to the binary predicate typepred(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)
and X has type A, thencall(P,X)
is a valid DCG phrase when the DCG is of type S. This type is equivalent topred(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)
andX
andY
are of typesA
andB
respectively, thencall(P,X,Y)
is a valid DCG phrase. And so on. You get the idea.*/