1
2%   File   : APPLIC.PL
3%   Author : Lawrence Byrd + Richard A. O'Keefe
4%   Updated: 4 August 1984 and Ken Johnson 11-8-87
5%   Purpose: Various "function" application routines based on apply/2.
6%   Needs  : append/3 from listut.pl
7
8%   Updated for SEPIA by Joachim Schimpf, ECRC, 14.2.91
9%   - introduced tools
10%   - made &-operator local
11
12:- module(applic).			% SEPIA header
13:- export
14    apply/2,
15    callable/1,
16    checkand/2,
17    checklist/2,
18    convlist/3,
19    exclude/3,
20    mapand/3,
21    maplist/3,
22    some/2,
23    somechk/2,
24    sublist/3.
25
26:- mode
27    apply(+, +),
28    callable(?),
29    checkand(+, +),
30    checklist(+, +),
31    convlist(+, +, ?),
32    exclude(+, +, ?),
33    mapand(+, ?, ?),
34    maplist(+, ?, ?),
35    some(+, ?),
36    somechk(+, +),
37    sublist(+, +, ?).
38
39% Operator declaration used below
40
41:-  op(920,xfy,&).      % Used for conjunction
42
43
44%   apply(Pred, Args)
45%   is the key to this whole module.  It is basically a variant of call/1
46%   (see the Dec-10 Prolog V3.43 manual) where some of the arguments may
47%   be already in the Pred, and the rest are passed in the list of Args.
48%   Thus apply(foo, [X,Y]) is the same as call(foo(X,Y)),
49%   and apply(foo(X), [Y]) is also the same as call(foo(X,Y)).
50%   BEWARE: any goal given to apply is handed off to call/1, which is the
51%   Prolog *interpreter*, so if you want to apply compiled predicates you
52%   MUST have :- public declarations for them.  The ability to pass goals
53%   around with some of their (initial) arguments already filled in is
54%   what makes apply/2 so useful.  Don't bother compiling anything that
55%   uses apply heavily, the compiler won't be able to help much.  LISP
56%   has the same problem.  Later Prolog systems may have a simpler link
57%   between compiled and interpreted code, or may fuse compilation and
58%   interpretation, so apply/2 may come back into its own.  At the moment,
59%   apply and the routines based on it are not well thought of.
60
61:- tool(apply/2, apply/3).
62
63apply(Pred, Args, Module) :-
64    (   atom(Pred),
65        Goal =.. [Pred|Args]
66    ;                   %   compound(Pred)
67        Pred =.. OldList,
68        append(OldList, Args, NewList),
69        Goal =.. NewList
70    ),  !,
71    call(Goal)@Module.
72
73
74
75%   callable(Term)
76%   succeeds when Term is something that it would make sense to give to
77%   call/1 or apply/2.  That is, Term must be an atom or a compound term;
78%   variables and integers are out.
79
80callable(Term) :-
81    nonvar(Term),
82    functor(Term, FunctionSymbol, _),
83    atom(FunctionSymbol).
84
85
86
87%   checkand(Pred, Conjunction)
88%   succeeds when Pred(Conjunct) succeeds for every Conjunct in the
89%   Conjunction.  All the *and predicates in this module assume that
90%   a&b&c&d is parsed as a&(b&(c&d)), and that the "null" conjunction
91%   is 'true'.  It is possible for this predicate, and most of the
92%   others, to backtrack and try alternative solutions.  If you do not
93%   want that to happen, copying one of these predicates and putting a
94%   cut in the suggested place will produce a tail-recursive version.
95%   The cuts in the *and predicates are there because "non-and" is
96%   defined by exclusion; they cannot be assigned types.
97
98:- tool(checkand/2, checkand/3).
99
100checkand(_, true, _) :- !.
101checkand(Pred, A&B, Module)  :- !,
102    apply(Pred, [A], Module),
103    checkand(Pred, B, Module).
104checkand(Pred, A, Module) :-
105    apply(Pred, [A], Module).
106
107
108
109%   checklist(Pred, List)
110%   suceeds when Pred(Elem) succeeds for each Elem in the List.
111%   In InterLisp, this is EVERY.  It is also MAPC.
112
113:- tool(checklist/2, checklist/3).
114
115checklist(_, [], _).
116checklist(Pred, [Head|Tail], Module) :-
117    apply(Pred, [Head], Module),
118    checklist(Pred, Tail, Module).
119
120
121
122%   mapand(Rewrite, OldConj, NewConj)
123%   succeeds when Rewrite is able to rewrite each conjunct of OldConj,
124%   and combines the results into NewConj.
125
126:- tool(mapand/3, mapand/4).
127
128mapand(_, true, true, _) :- !.
129mapand(Pred, Old&Olds, New&News, Module) :- !,
130    apply(Pred, [Old,New], Module),
131    mapand(Pred, Olds, News, Module).
132mapand(Pred, Old, New, Module) :-
133    apply(Pred, [Old,New], Module).
134
135
136
137%   maplist(Pred, OldList, NewList)
138%   succeeds when Pred(Old,New) succeeds for each corresponding
139%   Old in OldList, New in NewList.  In InterLisp, this is MAPCAR.
140%   It is also MAP2C.  Isn't bidirectionality wonderful?
141
142:- tool(maplist/3, maplist/4).
143
144maplist(_, [], [], _).
145maplist(Pred, [Old|Olds], [New|News], Module) :-
146    apply(Pred, [Old,New], Module),
147    maplist(Pred, Olds, News, Module).
148
149
150
151%   convlist(Rewrite, OldList, NewList)
152%   is a sort of hybrid of maplist/3 and sublist/3.
153%   Each element of NewList is the image under Rewrite of some
154%   element of OldList, and order is preserved, but elements of
155%   OldList on which Rewrite is undefined (fails) are not represented.
156%   Thus if foo(X,Y) :- integer(X), Y is X+1.
157%   then convlist(foo, [1,a,0,joe(99),101], [2,1,102]).
158
159:- tool(convlist/3, convlist/4).
160
161convlist(_, [], [], _).
162convlist(Pred, [Old|Olds], NewList, Module) :-
163    apply(Pred, [Old,New], Module),
164    !,
165    NewList = [New|News],
166    convlist(Pred, Olds, News, Module).
167convlist(Pred, [_|Olds], News, Module) :-
168    convlist(Pred, Olds, News, Module).
169
170
171
172%   exclude(Pred, List, SubList)
173%   succeeds when SubList is the SubList of List containing all the
174%   elements for which Pred(Elem) is *false*.  That is, it removes
175%   all the elements satisfying Pred.  Efficiency would be somewhat
176%   improved if the List argument came first, but this argument order
177%   was copied from the older sublist/3 predicate, and let's face it,
178%   apply/2 isn't stupendously efficient itself.
179
180:- tool(exclude/3, exclude/4).
181
182exclude(_, [], [], _).
183exclude(Pred, [Head|List], SubList, Module) :-
184    apply(Pred, [Head], Module),
185    !,
186    exclude(Pred, List, SubList, Module).
187exclude(Pred, [Head|List], [Head|SubList], Module) :-
188    exclude(Pred, List, SubList, Module).
189
190
191
192%   some(Pred, List)
193%   succeeds when Pred(Elem) succeeds for some Elem in List.  It will
194%   try all ways of proving Pred for each Elem, and will try each Elem
195%   in the List.  somechk/2 is to some/2 as memberchk/2 is to member/2;
196%   you are more likely to want somechk with its single solution.
197%   In InterLisp this is SOME.
198
199:- tool(some/2, some/3).
200
201some(Pred, [Head|_], Module) :-
202    apply(Pred, [Head], Module).
203some(Pred, [_|Tail], Module) :-
204    some(Pred, Tail, Module).
205
206
207:- tool(somechk/2, somechk/3).
208
209somechk(Pred, [Head|_], Module) :-
210    apply(Pred, [Head], Module),
211    !.
212somechk(Pred, [_|Tail], Module) :-
213    somechk(Pred, Tail, Module).
214
215
216
217%   sublist(Pred, List, SubList)
218%   succeeds when SubList is the sub-sequence of the List containing all
219%   the Elems of List for which Pred(Elem) succeeds.
220
221:- tool(sublist/3, sublist/4).
222
223sublist(_, [], [], _).
224sublist(Pred, [Head|List], SubList, Module) :-
225    apply(Pred, [Head], Module),
226    !,
227    SubList = [Head|Rest],
228    sublist(Pred, List, Rest, Module).
229sublist(Pred, [_|List], SubList, Module) :-
230    sublist(Pred, List, SubList, Module).
231
232
233
234