1% ----------------------------------------------------------------------
2% BEGIN LICENSE BLOCK
3% Version: CMPL 1.1
4%
5% The contents of this file are subject to the Cisco-style Mozilla Public
6% License Version 1.1 (the "License"); you may not use this file except
7% in compliance with the License.  You may obtain a copy of the License
8% at www.eclipse-clp.org/license.
9%
10% Software distributed under the License is distributed on an "AS IS"
11% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See
12% the License for the specific language governing rights and limitations
13% under the License.
14%
15% The Original Code is  The ECLiPSe Constraint Logic Programming System.
16% The Initial Developer of the Original Code is  Cisco Systems, Inc.
17% Portions created by the Initial Developer are
18% Copyright (C) 1995-2006 Cisco Systems, Inc.  All Rights Reserved.
19%
20% Contributor(s): ECRC GmbH
21% Contributor(s): IC-Parc, Imperal College London
22%
23% END LICENSE BLOCK
24%
25% System:	ECLiPSe Constraint Logic Programming System
26% Version:	$Id: apply_macros.pl,v 1.4 2013/02/09 20:27:57 jschimpf Exp $
27% ----------------------------------------------------------------------
28
29:- module(apply_macros).
30
31:- comment(categories, ["Algorithms","Programming Utilities"]).
32:- comment(summary, "Utilities to apply a predicate to all elements of a list resp. all subterms of a term").
33:- comment(author, "Joachim Schimpf, ECRC Munich").
34:- comment(copyright, "Cisco Systems, Inc").
35:- comment(date, "$Date: 2013/02/09 20:27:57 $").
36:- comment(desc, html("
37    Note that this library is largely superseded by the do-loop construct!
38    <P>
39    A collection of utilities to apply a predicate to
40    all elements of a list resp. all subterm of a term.
41    To avoid performance degradation due to apply/2,
42    they are implemented as macros, i.e. they are specialized
43    into auxiliary predicates without metacalls, and the
44    calls are translated into calls of the auxiliary predicates.")
45    ).
46
47:- export
48	fromto/4,
49	maplist/3,
50	mapstream/3,
51	mapargs/3,
52	appnodes/2,
53	sumargs/4,
54	checklist/2,
55	applist/2,
56	selectlist/3,
57	sumlist/4,
58	sumnodes/4.
59
60
61:- comment(fromto/4, [template:"fromto(+From, +To, +Step, +Pred)",
62    summary:"Call Pred with the numbers From..To in increments of Step"
63    ]).
64:- comment(maplist/3, [template:"maplist(+Pred, +ListIn, ?ListOut)",
65    summary:"Create new list by applying a predicate to all list elements",
66    eg:"maplist(times(3), [1,2,3,4], [3,6,9,12])."
67    ]).
68:- comment(mapstream/3, [template:"mapstream(+Pred, ?ListIn, ?ListOut)",
69    summary:"Like maplist/3, but delays if ListIn is not complete"
70    ]).
71:- comment(mapargs/3, [template:"mapargs(+Pred, +TermIn, ?TermOut)",
72    summary:"Create new term by applying a predicate to all arguments",
73    eg:"mapargs(atom_string, s(a,b,c), s(\"a\",\"b\",\"c\"))."
74    ]).
75:- comment(appnodes/2, [template:"appnodes(+Pred, +Term)",
76    summary:"Call Pred on all Subterms of Term (depth-first and left-to-right order)"
77    ]).
78:- comment(sumargs/4, [template:"sumargs(+Pred, +Term, ?AccIn, ?AccOut)",
79    summary:"Call Pred on all arguments of Term and collect a result in Accumulator",
80    desc:"The traversal order is unspecified!"
81    ]).
82:- comment(checklist/2, [template:"checklist(+Pred, +List)",
83    summary:"Apply a predicate to all list elements",
84    eg:"checklist(<(0), [1,2,3])."
85    ]).
86:- comment(applist/2, [template:"applist(+Pred, +List)",
87    summary:"Apply a predicate to all list elements",
88    eg:"applist(<(0), [1,2,3])."
89    ]).
90:- comment(selectlist/3, [template:"selectlist(+Pred, +ListIn, ?ListOut)",
91    summary:"Creates output list of all list elements that pass a given test",
92    eg:"selectlist(<(0), [1,0,-2,3], [1,3])."
93    ]).
94:- comment(sumlist/4, [template:"sumlist(+Pred, +List, ?AccIn, ?AccOut)",
95    summary:"Call Pred on all element of List and collect a result in Accumulator",
96    eg:"
97	sumlist(plus, [1,2,3,4], 1, 10).
98	sumlist(times, [1,2,3,4], 1, 24)."
99    ]).
100:- comment(sumnodes/4, [template:"sumnodes(+Pred, +Term, ?AccIn, ?AccOut)",
101    summary:"Call Pred on all Subterms of Term and collect a result in Accumulator",
102    desc:"The traversal is depth-first and left-to-right",
103    eg:"
104	sumnodes(vars, s(1,t(X,2),[Y]), [], [X,Y]).
105	where
106	    vars(X, Vars, [X|Vars]) :- var(X), !.
107	    vars(_, Vars, Vars).
108
109	or even more elegant using grammar rules:
110
111	sumnodes(vars, s(1,t(X,2),[Y]), [X,Y], []).
112	where
113	    vars(X) --> {var(X)} -> [X];[]."
114    ]).
115
116
117:- inline(fromto/4, t_fromto/3).
118:- inline(maplist/3, t_maplist/3).
119:- inline(mapstream/3, t_mapstream/3).
120:- inline(mapargs/3, t_mapargs/3).
121:- inline(appnodes/2, t_appnodes/3).
122:- inline(sumargs/4, t_sumargs/3).
123:- inline(checklist/2, t_checklist/3).
124:- inline(applist/2, t_applist/3).
125:- inline(selectlist/3, t_selectlist/3).
126:- inline(sumlist/4, t_sumlist/3).
127:- inline(sumnodes/4, t_sumnodes/3).
128
129
130t_maplist(maplist(Pred, In, Out), NewGoal, Module) :-
131	callable(Pred),
132	!,
133	analyse_pred(Pred, VarArgs, GenPred, GenVarArgs, Pattern),
134	aux_pred_name(maplist, Pattern, NewName),
135	append(VarArgs, [In, Out], NewGoalArgs),	% make new goal
136	NewGoal =.. [NewName|NewGoalArgs],
137	append_args(NewName, GenVarArgs, HeadPrefix),	% make new predicate
138	append_args(HeadPrefix, [[], []], NilClause),
139	append_args(HeadPrefix, [[Old|Olds], [New|News]], LoopHead),
140	append_args(GenPred, [Old, New], Apply),
141	append_args(HeadPrefix, [Olds, News], Recursion),
142	compile_aux([
143		NilClause,
144		(LoopHead :- Apply, Recursion)
145	], Module).
146
147
148t_fromto(fromto(From, To, Step, Pred), NewGoal, Module) :-
149	callable(Pred),
150	number(Step),
151	!,
152	analyse_pred(Pred, VarArgs, GenPred, GenVarArgs, Pattern),
153	aux_pred_name(fromto, (Step,Pattern), NewName),
154	append(VarArgs, [From,To], NewGoalArgs),	% make new goal
155	NewGoal =.. [NewName|NewGoalArgs],
156	append_args(NewName, GenVarArgs, HeadPrefix),	% make new predicate
157	append_args(HeadPrefix, [From0, To0], LoopHead),
158	append_args(GenPred, [From0], Apply),
159	append_args(HeadPrefix, [From1,To0], Recursion),
160	( Step >= 0 -> Cond = (From0=<To0) ; Cond = (From0>=To0) ),
161	compile_aux([
162		(LoopHead :-
163		    ( Cond ->
164		    	Apply, From1 is From0+Step, Recursion
165		    ;
166		    	true
167		    )
168		)
169	], Module).
170
171
172% similar to maplist, but with a delay clause
173
174t_mapstream(mapstream(Pred, In, Out), NewGoal, Module) :-
175	callable(Pred),
176	!,
177	analyse_pred(Pred, VarArgs, GenPred, GenVarArgs, Pattern),
178	aux_pred_name(mapstream, Pattern, NewName),
179	append(VarArgs, [In, Out], NewGoalArgs),	% make new goal
180	NewGoal =.. [NewName|NewGoalArgs],
181	append_args(NewName, GenVarArgs, HeadPrefix),	% make new predicate
182	append_args(HeadPrefix, [[], []], NilClause),
183	append_args(HeadPrefix, [InStream, _], DelayHead),
184	append_args(HeadPrefix, [[Old|Olds], News], LoopHead),
185	append_args(GenPred, [Old, New], Apply),
186	append_args(HeadPrefix, [Olds, News0], Recursion),
187	compile_aux([
188		(delay DelayHead if var(InStream)),
189		NilClause,
190		(LoopHead :- Apply, News = [New|News0], Recursion)
191	], Module).
192
193
194
195% selectlist/3 creates output list of all list elements that pass a given test
196% e.g. selectlist(<(0), [5,-3,0,2,-7], [5, 2])
197
198t_selectlist(selectlist(Pred, In, Out), NewGoal, Module) :-
199	callable(Pred),
200	!,
201	analyse_pred(Pred, VarArgs, GenPred, GenVarArgs, Pattern),
202	aux_pred_name(selectlist, Pattern, NewName),
203	append(VarArgs, [In, Out], NewGoalArgs),	% make new goal
204	NewGoal =.. [NewName|NewGoalArgs],
205	append_args(NewName, GenVarArgs, HeadPrefix),	% make new predicate
206	append_args(HeadPrefix, [[], []], NilClause),
207	append_args(HeadPrefix, [[Old|Olds], News], LoopHead),
208	append_args(GenPred, [Old], Apply),
209	append_args(HeadPrefix, [Olds, News0], Recursion),
210	compile_aux([
211		NilClause,
212		(LoopHead :-
213			(Apply -> News = [Old|News0] ; News = News0),
214			Recursion)
215	], Module).
216
217
218
219t_applist(applist(Pred, List), NewGoal, Module) :-
220	callable(Pred),
221	!,
222	analyse_pred(Pred, VarArgs, GenPred, GenVarArgs, Pattern),
223	aux_pred_name(applist, Pattern, NewName),
224	append(VarArgs, [List], NewGoalArgs),		% make new goal
225	NewGoal =.. [NewName|NewGoalArgs],
226	append_args(NewName, GenVarArgs, HeadPrefix),	% make new predicate
227	append_args(HeadPrefix, [[]], NilClause),
228	append_args(HeadPrefix, [[Old|Olds]], LoopHead),
229	append_args(GenPred, [Old], Apply),
230	append_args(HeadPrefix, [Olds], Recursion),
231	compile_aux([
232		NilClause,
233		(LoopHead :- Apply, Recursion)
234	], Module).
235
236
237t_checklist(checklist(Pred, List), NewGoal, Module) :-
238	t_applist(applist(Pred, List), NewGoal, Module).
239
240t_sumlist(sumlist(Pred, List, AccIn, AccOut), NewGoal, Module) :-
241	callable(Pred),
242	!,
243	analyse_pred(Pred, VarArgs, GenPred, GenVarArgs, Pattern),
244	aux_pred_name(sumlist, Pattern, NewName),
245	append(VarArgs, [List, AccIn, AccOut], NewGoalArgs),	% make new goal
246	NewGoal =.. [NewName|NewGoalArgs],
247	append_args(NewName, GenVarArgs, HeadPrefix),	% make new predicate
248	append_args(HeadPrefix, [[], Acc0, Acc0], NilClause),
249	append_args(HeadPrefix, [[Old|Olds], Acc10, Acc12], LoopHead),
250	append_args(GenPred, [Old, Acc10, Acc11], Apply),
251	append_args(HeadPrefix, [Olds, Acc11, Acc12], Recursion),
252	compile_aux([
253		NilClause,
254		(LoopHead :- Apply, Recursion)
255	], Module).
256
257
258t_mapargs(mapargs(Pred, In, Out), NewGoal, Module) :-
259	callable(Pred),
260	!,
261	analyse_pred(Pred, VarArgs, GenPred, GenVarArgs, Pattern),
262	aux_pred_name(mapargs, Pattern, NewName),
263	append(VarArgs, [In, Out], NewGoalArgs),	% make new goal
264	NewGoal =.. [NewName|NewGoalArgs],
265	append_args(NewName, GenVarArgs, HeadPrefix),	% make new predicate
266	append_args(HeadPrefix, [Old, New], TopHead),
267	append_args(HeadPrefix, [_, _, 0], NullHead),
268	append_args(HeadPrefix, [Old, New, N0], LoopHead),
269	append_args(GenPred, [OldArg, NewArg], Apply),
270	append_args(HeadPrefix, [Old, New, N], Recursion),
271	compile_aux([
272		(TopHead :-
273			functor(Old, F, N),
274			functor(New, F, N),
275			Recursion
276			),
277		(NullHead :- !),
278		(LoopHead :-
279			arg(N0, Old, OldArg),
280			arg(N0, New, NewArg),
281			N is N0-1,
282			Apply,
283			Recursion)
284	], Module).
285
286
287% appnodes(Pred, Term)
288% call Pred on all Subterms of Term
289% traversal is depth-first and left-to-right
290
291t_appnodes(appnodes(Pred, Term), NewGoal, Module) :-
292	callable(Pred),
293	!,
294	analyse_pred(Pred, VarArgs, GenPred, GenVarArgs, Pattern),
295	aux_pred_name(appnodes, Pattern, NewName),
296	aux_pred_name(appnodes_list, Pattern, NewNameList),
297	append(VarArgs, [Term], NewGoalArgs),	% make new goal
298	NewGoal =.. [NewName|NewGoalArgs],
299	append_args(NewName, GenVarArgs, HeadPrefix),	% make new predicate
300	append_args(NewNameList, GenVarArgs, HeadPrefixList),
301	append_args(HeadPrefix, [T], HeadA1),
302	append_args(GenPred,    [T], Apply),
303	append_args(HeadPrefixList, [[]], HeadL1),
304	append_args(HeadPrefixList, [[T|Args]], HeadL2),
305	append_args(HeadPrefixList, [T], RecList),
306	append_args(HeadPrefixList, [Args], RecListA),
307	compile_aux([
308		(HeadA1 :-
309			(atomic(T); var(T)),
310			Apply
311			),
312		(HeadA1 :-
313			compound(T),
314			T = [_|_],
315			!,
316			Apply,
317			RecList),
318		(HeadA1 :-
319			compound(T),
320			Apply,
321			T =.. [_|Args],
322			RecListA),
323		HeadL1,
324		(HeadL2 :-
325			HeadA1,
326			RecListA)
327	], Module).
328
329
330% sumnodes(Pred, Term, AccIn, AccOut)
331% call Pred on all Subterms of Term and collect a result in Accumulator
332% traversal is depth-first and left-to-right
333
334t_sumnodes(sumnodes(Pred, Term, AccIn, AccOut), NewGoal, Module) :-
335	callable(Pred),
336	!,
337	analyse_pred(Pred, VarArgs, GenPred, GenVarArgs, Pattern),
338	aux_pred_name(sumnodes, Pattern, NewName),
339	append(VarArgs, [Term, AccIn, AccOut], NewGoalArgs),	% make new goal
340	NewGoal =.. [NewName|NewGoalArgs],
341	append_args(NewName, GenVarArgs, HeadPrefix),	% make new predicate
342	append_args(HeadPrefix, [T, A0, A2], Head0),
343	append_args(GenPred,    [T, A0, A1], Apply),
344	append_args(HeadPrefix, [T, A1, A2, 0, N], Call0),
345	append_args(HeadPrefix, [T, A1, A3, N0, Ar], Head1),
346	append_args(HeadPrefix, [Arg, A1, A2], Call1),
347	append_args(HeadPrefix, [T, A2, A3, N, Ar], Recursion),
348	compile_aux([
349		(Head0 :-
350			Apply,
351			(compound(T) ->
352			    functor(T, _, N),
353			    Call0
354			;
355			    A1 = A2
356			)),
357		(Head1 :-
358			N0 < Ar ->
359			    N is N0 + 1,
360			    arg(N, T, Arg),
361			    Call1,
362			    Recursion
363			;
364			    A1 = A3)
365	], Module).
366
367
368% sumargs(Pred, Term, AccIn, AccOut)
369% call Pred on all arguments of Term and collect a result in Accumulator
370% traversal order is unspecified!
371
372t_sumargs(sumargs(Pred, Term, AccIn, AccOut), NewGoal, Module) :-
373	callable(Pred),
374	!,
375	analyse_pred(Pred, VarArgs, GenPred, GenVarArgs, Pattern),
376	aux_pred_name(sumargs, Pattern, NewName),
377	append(VarArgs, [Term, AccIn, AccOut], NewGoalArgs),	% make new goal
378	NewGoal =.. [NewName|NewGoalArgs],
379	append_args(NewName, GenVarArgs, HeadPrefix),	% make new predicate
380	append_args(HeadPrefix, [T, A0, A1], Head0),
381	append_args(HeadPrefix, [T, A0, A1, N], Call0),
382	append_args(HeadPrefix, [_, A0, A1, 0], NullHead),
383	append_args(HeadPrefix, [T, A1, A3, N], Head1),
384	append_args(GenPred,    [Arg, A1, A2], Apply),
385	append_args(HeadPrefix, [T, A2, A3, N1], Recursion),
386	compile_aux([
387		(Head0 :-
388			functor(T, _, N),
389			Call0),
390		(NullHead :-
391			!, A0 = A1),
392		(Head1 :-
393			arg(N, T, Arg),
394			N1 is N - 1,
395			Apply,
396			Recursion)
397	], Module).
398
399
400
401% utilities
402
403compile_aux(Clauses, Module) :-
404	Clauses = [Clause|_],
405	( Clause = (Head :- _) -> true
406	; Clause = (delay Head if _) -> true
407	; Clause = Head ),
408	functor(Head, F, N),
409	( is_predicate(F/N)@Module ->
410%	    printf("*** Reusing auxiliary predicate %Qw\n%b", [F/N]),
411	    true
412	;
413	    printf("*** Creating auxiliary predicate %Qw\n%b", [F/N]),
414%	    write_clauses(Clauses),
415	    sepia_kernel:nested_compile_term(Clauses)@Module,
416	    set_flag(F/N, auxiliary, on)@Module
417	).
418
419write_clauses([]).
420write_clauses([C|Cs]) :-
421	writeclause(C),
422	write_clauses(Cs).
423
424
425append_args(Term, Args, NewTerm) :-
426	atom(Term),
427	NewTerm =.. [Term|Args].
428append_args(Term, Args, NewTerm) :-
429	compound(Term),
430	Term =.. OldList,
431	append(OldList, Args, NewList),
432	NewTerm =.. NewList.
433
434
435:- mode analyse_pred(+,-,-,-,-).
436analyse_pred(Pred, VarArgs, GenPred, GenVarArgs, Pattern) :-
437	functor(Pred, F, N),
438	functor(Pattern, F, N),
439	functor(GenPred, F, N),
440	analyse_arg(Pred, VarArgs, GenPred, GenVarArgs, Pattern, 0, N).
441
442:- mode analyse_arg(+,-,+,-,+,+,+).
443analyse_arg(_Pred, [], _GenPred, [], _Pattern, Ar, Ar) :- !.
444analyse_arg(Pred, VarArgs, GenPred, GenVarArgs, Pattern, N0, Ar) :-
445	N is N0+1,
446	arg(N, Pred, Arg),
447	( nonground(Arg) ->
448	    arg(N, Pattern, '_'),
449	    VarArgs = [Arg|VarArgs0],
450	    GenVarArgs = [_Var|GenVarArgs0],
451	    arg(N, GenPred, _Var)
452	;
453	    arg(N, Pattern, Arg),
454	    arg(N, GenPred, Arg),
455	    VarArgs = VarArgs0,
456	    GenVarArgs = GenVarArgs0
457	),
458	analyse_arg(Pred, VarArgs0, GenPred, GenVarArgs0, Pattern, N, Ar).
459
460
461aux_pred_name(Name, Pattern, NewName) :-
462	open("", string, S),
463	printf(S, "%a(%w)", [Name, Pattern]),
464	get_stream_info(S, name, NewNameS),
465	close(S),
466	atom_string(NewName, NewNameS).
467
468
469%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
470%
471%  Definitions for Metacalls
472%
473%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
474
475:- local maplist_body/4.	% hide the one from lib(lists)
476:- tool(maplist/3, maplist_body/4).
477
478maplist_body(_, [], [], _).
479maplist_body(Pred, [In|ListIn], [Out|ListOut], Module) :-
480    call(Pred, In, Out)@Module,
481    maplist_body(Pred, ListIn, ListOut, Module).
482
483:- tool(mapstream/3, mapstream_body/4).
484
485delay mapstream_body(_, L, _, _) if var(L).
486mapstream_body(_, [], [], _).
487mapstream_body(Pred, [In|ListIn], [Out|ListOut], Module) :-
488    call(Pred, In, Out)@Module,
489    mapstream_body(Pred, ListIn, ListOut, Module).
490
491:- tool(mapargs/3, mapargs_body/4).
492
493mapargs_body(Pred, TermIn, TermOut, Module) :-
494    functor(TermIn, F, N),
495    functor(TermOut, F, N),
496    mapargs_args(Pred, TermIn, TermOut, N, Module).
497
498mapargs_args(_, _, _, 0, _) :- !.
499mapargs_args(Pred, TermIn, TermOut, I, Module) :-
500    arg(I, TermIn, InArg),
501    arg(I, TermOut, OutArg),
502    I1 is I-1,
503    call(Pred, InArg, OutArg)@Module,
504    mapargs_args(Pred, TermIn, TermOut, I1, Module).
505
506:- tool(appnodes/2, appnodes_body/3).
507
508appnodes_body(Pred, Term, Module) :-
509    (atomic(Term); var(Term)),
510    call(Pred, Term)@Module.
511appnodes_body(Pred, Term, Module) :-
512    compound(Term),
513    Term = [_|_],
514    !,
515    call(Pred, Term)@Module,
516    appnodes_list(Pred, Term, Module).
517appnodes_body(Pred, Term, Module) :-
518    compound(Term),
519    call(Pred, Term)@Module,
520    Term =.. [_|Args],
521    appnodes_list(Pred, Args, Module).
522
523appnodes_list(_, [], _).
524appnodes_list(Pred, [Term|Args], Module) :-
525    appnodes_body(Pred, Term, Module),
526    appnodes_list(Pred, Args, Module).
527
528:- tool(sumargs/4, sumargs_body/5).
529
530sumargs_body(Pred, Term, A0, A1, Module) :-
531    functor(Term, _, N),
532    sumargs(Pred, Term, A0, A1, N, Module).
533
534sumargs(_, _, A0, A1, 0, _) :-
535    !,
536    A0 = A1.
537sumargs(Pred, Term, A1, A3, N, Module) :-
538    arg(N, Term, Arg),
539    N1 is N - 1,
540    call(Pred, Arg, A1, A2)@Module,
541    sumargs(Pred, Term, A2, A3, N1, Module).
542
543:- tool(applist/2, applist_body/3).
544:- tool(checklist/2, applist_body/3).
545
546applist_body(_, [], _).
547applist_body(Pred, [In|ListIn], Module) :-
548    append_args(Pred, [In], Goal),
549    call(Goal)@Module,
550    applist_body(Pred, ListIn, Module).
551
552:- tool(selectlist/3, selectlist_body/4).
553
554selectlist_body(_, [], [], _).
555selectlist_body(Pred, [In|ListIn], ListOut, Module) :-
556    (call(Pred, In)@Module ->
557	ListOut = [In|NewListOut]
558    ;
559	ListOut = NewListOut
560    ),
561    selectlist_body(Pred, ListIn, NewListOut, Module).
562
563:- tool(sumlist/4, sumlist_body/5).
564
565sumlist_body(_, [], Acc, Acc, _).
566sumlist_body(Pred, [H|T], AccIn, AccOut, Module) :-
567    call(Pred, H, AccIn, A1)@Module,
568    sumlist_body(Pred, T, A1, AccOut, Module).
569
570:- tool(sumnodes/4, sumnodes_body/5).
571
572sumnodes_body(Pred, Term, A0, A2, Module) :-
573    call(Pred, Term, A0, A1)@Module,
574    (compound(Term) ->
575	functor(Term, _, N),
576	sumnodes(Pred, Term, A1, A2, 0, N, Module)
577    ;	% simple term or variable
578	A1 = A2
579    ).
580
581sumnodes(Pred, Term, A1, A3, N0, Ar, Module) :-
582    N0 < Ar ->
583	N is N0+1,
584	arg(N, Term, Arg),
585	sumnodes_body(Pred, Arg, A1, A2, Module),
586	sumnodes(Pred, Term, A2, A3, N, Ar, Module)
587    ;
588	A1 = A3.
589
590:- tool(fromto/4, fromto_body/5).
591
592fromto_body(From, To, Step, Pred, Module) :-
593	( sgn(Step) =:= sgn(From-To) ->
594	    true
595	;
596	    call(Pred, From)@Module,
597	    From1 is From+Step,
598	    fromto_body(From1, To, Step, Pred, Module)
599	).
600
601