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