1/* Part of SWI-Prolog 2 3 Author: Jan Wielemaker 4 E-mail: jan@swi-prolog.org 5 WWW: https://www.swi-prolog.org 6 Copyright (c) 2007-2026, University of Amsterdam 7 VU University Amsterdam 8 SWI-Prolog Solutions b.v. 9 All rights reserved. 10 11 Redistribution and use in source and binary forms, with or without 12 modification, are permitted provided that the following conditions 13 are met: 14 15 1. Redistributions of source code must retain the above copyright 16 notice, this list of conditions and the following disclaimer. 17 18 2. Redistributions in binary form must reproduce the above copyright 19 notice, this list of conditions and the following disclaimer in 20 the documentation and/or other materials provided with the 21 distribution. 22 23 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 27 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 28 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 29 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 30 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 31 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 33 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34 POSSIBILITY OF SUCH DAMAGE. 35*/ 36 37:- module(apply, 38 [ include/3, % :Pred, +List, -Ok 39 exclude/3, % :Pred. +List, -NotOk 40 partition/4, % :Pred, +List, -Included, -Excluded 41 partition/5, % :Pred, +List, ?Less, ?Equal, ?Greater 42 maplist/2, % :Pred, +List 43 maplist/3, % :Pred, ?List, ?List 44 maplist/4, % :Pred, ?List, ?List, ?List 45 maplist/5, % :Pred, ?List, ?List, ?List, ?List 46 convlist/3, % :Pred, +List, -List 47 foldl/4, % :Pred, +List, ?V0, ?V 48 foldl/5, % :Pred, +List1, +List2, ?V0, ?V 49 foldl/6, % :Pred, +List1, +List2, +List3, ?V0, ?V 50 foldl/7, % :Pred, +List1, +List2, +List3, +List4, 51 % ?V0, ?V 52 scanl/4, % :Pred, +List, ?V0, ?Vs 53 scanl/5, % :Pred, +List1, +List2, ?V0, ?Vs 54 scanl/6, % :Pred, +List1, +List2, +List3, ?V0, ?Vs 55 scanl/7 % :Pred, +List1, +List2, +List3, +List4, 56 % ?V0, ?Vs 57 ]). 58:- autoload(library(error),[must_be/2]). 59:- set_prolog_flag(generate_debug_info, false).
81:- meta_predicate
82 include(, , ),
83 exclude(, , ),
84 partition(, , , ),
85 partition(, , , , ),
86 maplist(, ),
87 maplist(, , ),
88 maplist(, , , ),
89 maplist(, , , , ),
90 convlist(, , ),
91 foldl(, , , ),
92 foldl(, , , , ),
93 foldl(, , , , , ),
94 foldl(, , , , , , ),
95 scanl(, , , ),
96 scanl(, , , , ),
97 scanl(, , , , , ),
98 scanl(, , , , , , ).call(Goal, Xi) succeeds.
110include(_, [], []). 111include(Goal, [X1|Xs1], Included) :- 112 ( call(Goal, X1) 113 -> Included = [X1|Included1] 114 ; Included = Included1 115 ), 116 include(Goal, Xs1, Included1).
call(Goal, Xi) fails.
126exclude(_, [], []). 127exclude(Goal, [X1|Xs1], Included) :- 128 ( call(Goal, X1) 129 -> Included = Included1 130 ; Included = [X1|Included1] 131 ), 132 exclude(Goal, Xs1, Included1).
call(Pred, X) succeeds and
Excluded contains the remaining elements.
143partition(_, [], [], []). 144partition(Pred, [H|T], Incl, Excl) :- 145 ( call(Pred, H) 146 -> Incl = [H|I], 147 partition(Pred, T, I, Excl) 148 ; Excl = [H|E], 149 partition(Pred, T, Incl, E) 150 ).
call(Pred, Xi, Place),
where Place must be unified to one of <, = or >.
Pred must be deterministic.
162partition(_, [], [], [], []). 163partition(Pred, [H|T], L, E, G) :- 164 call(Pred, H, Diff), 165 partition_(Diff, H, Pred, T, L, E, G). 166 167partition_(<, H, Pred, T, L, E, G) :- 168 !, 169 L = [H|Rest], 170 partition(Pred, T, Rest, E, G). 171partition_(=, H, Pred, T, L, E, G) :- 172 !, 173 E = [H|Rest], 174 partition(Pred, T, L, Rest, G). 175partition_(>, H, Pred, T, L, E, G) :- 176 !, 177 G = [H|Rest], 178 partition(Pred, T, L, E, Rest). 179partition_(Diff, _, _, _, _, _, _) :- 180 must_be(oneof([<,=,>]), Diff). 181 182 183 /******************************* 184 * MAPLIST * 185 *******************************/
maplist(G, [X_11, ..., X_1n],
[X_21, ..., X_2n],
...,
[X_m1, ..., X_mn]) :-
call(G, X_11, ..., X_m1),
call(G, X_12, ..., X_m2),
...
call(G, X_1n, ..., X_mn).
This family of predicates is deterministic iff Goal is deterministic
and List1 is a proper list, i.e., a list that ends in [].
209maplist(_, []). 210maplist(Goal, [Elem|Tail]) :- 211 call(Goal, Elem), 212 maplist(Goal, Tail). 213 214maplist(_, [], []). 215maplist(Goal, [Elem1|Tail1], [Elem2|Tail2]) :- 216 call(Goal, Elem1, Elem2), 217 maplist(Goal, Tail1, Tail2). 218 219maplist(_, [], [], []). 220maplist(Goal, [Elem1|Tail1], [Elem2|Tail2], [Elem3|Tail3]) :- 221 call(Goal, Elem1, Elem2, Elem3), 222 maplist(Goal, Tail1, Tail2, Tail3). 223 224maplist(_, [], [], [], []). 225maplist(Goal, [Elem1|Tail1], [Elem2|Tail2], [Elem3|Tail3], [Elem4|Tail4]) :- 226 call(Goal, Elem1, Elem2, Elem3, Elem4), 227 maplist(Goal, Tail1, Tail2, Tail3, Tail4).
call(Goal, ElemIn, _)
fails are omitted from ListOut. For example (using library(yall)):
?- convlist([X,Y]>>(integer(X), Y is X^2),
[3, 5, foo, 2], L).
L = [9, 25, 4].
244convlist(_, [], []). 245convlist(Goal, [H0|T0], ListOut) :- 246 ( call(Goal, H0, H) 247 -> ListOut = [H|T], 248 convlist(Goal, T0, T) 249 ; convlist(Goal, T0, ListOut) 250 ). 251 252 253 /******************************* 254 * FOLDL * 255 *******************************/
foldl family of predicates is defined as
follows, with V0 an initial value and V the final value of the
folding operation:
foldl(G, [X_11, ..., X_1n],
[X_21, ..., X_2n],
...,
[X_m1, ..., X_mn], V0, V) :-
call(G, X_11, ..., X_m1, V0, V1),
call(G, X_12, ..., X_m2, V1, V2),
...
call(G, X_1n, ..., X_mn, V<n-1>, V).
No implementation for a corresponding foldr is given. A foldr
implementation would consist in first calling reverse/2 on each of
the m input lists, then applying the appropriate foldl. This is
actually more efficient than using a properly programmed-out
recursive algorithm that cannot be tail-call optimized.
285foldl(_, [], V, V). 286foldl(Goal, [H|T], V0, V) :- 287 call(Goal, H, V0, V1), 288 foldl(Goal, T, V1, V). 289 290 291foldl(_, [], [], V, V). 292foldl(Goal, [H1|T1], [H2|T2], V0, V) :- 293 call(Goal, H1, H2, V0, V1), 294 foldl(Goal, T1, T2, V1, V). 295 296 297foldl(_, [], [], [], V, V). 298foldl(Goal, [H1|T1], [H2|T2], [H3|T3], V0, V) :- 299 call(Goal, H1, H2, H3, V0, V1), 300 foldl(Goal, T1, T2, T3, V1, V). 301 302 303foldl(_, [], [], [], [], V, V). 304foldl(Goal, [H1|T1], [H2|T2], [H3|T3], [H4|T4], V0, V) :- 305 call(Goal, H1, H2, H3, H4, V0, V1), 306 foldl(Goal, T1, T2, T3, T4, V1, V). 307 308 309 /******************************* 310 * SCANL * 311 *******************************/
scanl family of predicates is defined as
follows, with V0 an initial value and V the final value of the
scanning operation:
scanl(G, [X_11, ..., X_1n],
[X_21, ..., X_2n],
...,
[X_m1, ..., X_mn], V0, [V0, V1, ..., Vn] ) :-
call(G, X_11, ..., X_m1, V0, V1),
call(G, X_12, ..., X_m2, V1, V2),
...
call(G, X_1n, ..., X_mn, V<n-1>, Vn).
scanl behaves like a foldl that collects the sequence of
values taken on by the Vx accumulator into a list.
338scanl(_, [], V, [V]). 339scanl(Goal, [H|T], V, [V|VT]) :- 340 call(Goal, H, V, VH), 341 scanl(Goal, T, VH, VT). 342 343 344scanl(_, [], [], V, [V]). 345scanl(Goal, [H1|T1], [H2|T2], V, [V|VT]) :- 346 call(Goal, H1, H2, V, VH), 347 scanl(Goal, T1, T2, VH, VT). 348 349 350scanl(_, [], [], [], V, [V]). 351scanl(Goal, [H1|T1], [H2|T2], [H3|T3], V, [V|VT]) :- 352 call(Goal, H1, H2, H3, V, VH), 353 scanl(Goal, T1, T2, T3, VH, VT). 354 355 356scanl(_, [], [], [], [], V, [V]). 357scanl(Goal, [H1|T1], [H2|T2], [H3|T3], [H4|T4], V, [V|VT]) :- 358 call(Goal, H1, H2, H3, H4, V, VH), 359 scanl(Goal, T1, T2, T3, T4, VH, VT). 360 361 362 /******************************* 363 * SANDBOX * 364 *******************************/ 365 366:- multifile 367 sandbox:safe_meta_predicate/1. 368 369safe_api(Name/Arity, sandbox:safe_meta_predicate(apply:Name/Arity)). 370 371term_expansion(safe_api, Clauses) :- 372 module_property(apply, exports(API)), 373 maplist(safe_api, API, Clauses). 374 375safe_api
Apply predicates on a list
This module defines meta-predicates that apply a predicate on all members of a list.
All predicates support partial application in the Goal argument. This means that these calls are identical:
apply_macros.plprovides compile-time expansion for part of this library.tests/library/test_apply.pl