1/* Part of SWI-Prolog 2 3 Author: Jan Wielemaker 4 E-mail: J.Wielemaker@vu.nl 5 WWW: http://www.swi-prolog.org 6 Copyright (c) 2007-2023, 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(Goal, List, Included) :- 111 include_(List, Goal, Included). 112 113include_([], _, []). 114include_([X1|Xs1], P, Included) :- 115 ( call(P, X1) 116 -> Included = [X1|Included1] 117 ; Included = Included1 118 ), 119 include_(Xs1, P, Included1).
call(Goal, Xi)
fails.
129exclude(Goal, List, Included) :- 130 exclude_(List, Goal, Included). 131 132exclude_([], _, []). 133exclude_([X1|Xs1], P, Included) :- 134 ( call(P, X1) 135 -> Included = Included1 136 ; Included = [X1|Included1] 137 ), 138 exclude_(Xs1, P, Included1).
call(Pred, X)
succeeds and
Excluded contains the remaining elements.
149partition(Pred, List, Included, Excluded) :- 150 partition_(List, Pred, Included, Excluded). 151 152partition_([], _, [], []). 153partition_([H|T], Pred, Incl, Excl) :- 154 ( call(Pred, H) 155 -> Incl = [H|I], 156 partition_(T, Pred, I, Excl) 157 ; Excl = [H|E], 158 partition_(T, Pred, Incl, E) 159 ).
call(Pred, Xi, Place)
,
where Place must be unified to one of <
, =
or >
.
Pred must be deterministic.
171partition(Pred, List, Less, Equal, Greater) :- 172 partition_(List, Pred, Less, Equal, Greater). 173 174partition_([], _, [], [], []). 175partition_([H|T], Pred, L, E, G) :- 176 call(Pred, H, Diff), 177 partition_(Diff, H, Pred, T, L, E, G). 178 179partition_(<, H, Pred, T, L, E, G) :- 180 !, 181 L = [H|Rest], 182 partition_(T, Pred, Rest, E, G). 183partition_(=, H, Pred, T, L, E, G) :- 184 !, 185 E = [H|Rest], 186 partition_(T, Pred, L, Rest, G). 187partition_(>, H, Pred, T, L, E, G) :- 188 !, 189 G = [H|Rest], 190 partition_(T, Pred, L, E, Rest). 191partition_(Diff, _, _, _, _, _, _) :- 192 must_be(oneof([<,=,>]), Diff). 193 194 195 /******************************* 196 * MAPLIST * 197 *******************************/
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 []
.
221maplist(Goal, List) :- 222 maplist_(List, Goal). 223 224maplist_([], _). 225maplist_([Elem|Tail], Goal) :- 226 call(Goal, Elem), 227 maplist_(Tail, Goal). 228 229maplist(Goal, List1, List2) :- 230 maplist_(List1, List2, Goal). 231 232maplist_([], [], _). 233maplist_([Elem1|Tail1], [Elem2|Tail2], Goal) :- 234 call(Goal, Elem1, Elem2), 235 maplist_(Tail1, Tail2, Goal). 236 237maplist(Goal, List1, List2, List3) :- 238 maplist_(List1, List2, List3, Goal). 239 240maplist_([], [], [], _). 241maplist_([Elem1|Tail1], [Elem2|Tail2], [Elem3|Tail3], Goal) :- 242 call(Goal, Elem1, Elem2, Elem3), 243 maplist_(Tail1, Tail2, Tail3, Goal). 244 245maplist(Goal, List1, List2, List3, List4) :- 246 maplist_(List1, List2, List3, List4, Goal). 247 248maplist_([], [], [], [], _). 249maplist_([Elem1|Tail1], [Elem2|Tail2], [Elem3|Tail3], [Elem4|Tail4], Goal) :- 250 call(Goal, Elem1, Elem2, Elem3, Elem4), 251 maplist_(Tail1, Tail2, Tail3, Tail4, Goal).
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].
268convlist(Goal, ListIn, ListOut) :- 269 convlist_(ListIn, ListOut, Goal). 270 271convlist_([], [], _). 272convlist_([H0|T0], ListOut, Goal) :- 273 ( call(Goal, H0, H) 274 -> ListOut = [H|T], 275 convlist_(T0, T, Goal) 276 ; convlist_(T0, ListOut, Goal) 277 ). 278 279 280 /******************************* 281 * FOLDL * 282 *******************************/
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.
312foldl(Goal, List, V0, V) :- 313 foldl_(List, Goal, V0, V). 314 315foldl_([], _, V, V). 316foldl_([H|T], Goal, V0, V) :- 317 call(Goal, H, V0, V1), 318 foldl_(T, Goal, V1, V). 319 320 321foldl(Goal, List1, List2, V0, V) :- 322 foldl_(List1, List2, Goal, V0, V). 323 324foldl_([], [], _, V, V). 325foldl_([H1|T1], [H2|T2], Goal, V0, V) :- 326 call(Goal, H1, H2, V0, V1), 327 foldl_(T1, T2, Goal, V1, V). 328 329 330foldl(Goal, List1, List2, List3, V0, V) :- 331 foldl_(List1, List2, List3, Goal, V0, V). 332 333foldl_([], [], [], _, V, V). 334foldl_([H1|T1], [H2|T2], [H3|T3], Goal, V0, V) :- 335 call(Goal, H1, H2, H3, V0, V1), 336 foldl_(T1, T2, T3, Goal, V1, V). 337 338 339foldl(Goal, List1, List2, List3, List4, V0, V) :- 340 foldl_(List1, List2, List3, List4, Goal, V0, V). 341 342foldl_([], [], [], [], _, V, V). 343foldl_([H1|T1], [H2|T2], [H3|T3], [H4|T4], Goal, V0, V) :- 344 call(Goal, H1, H2, H3, H4, V0, V1), 345 foldl_(T1, T2, T3, T4, Goal, V1, V). 346 347 348 /******************************* 349 * SCANL * 350 *******************************/
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.
377scanl(Goal, List, V0, [V0|Values]) :- 378 scanl_(List, Goal, V0, Values). 379 380scanl_([], _, _, []). 381scanl_([H|T], Goal, V, [VH|VT]) :- 382 call(Goal, H, V, VH), 383 scanl_(T, Goal, VH, VT). 384 385 386scanl(Goal, List1, List2, V0, [V0|Values]) :- 387 scanl_(List1, List2, Goal, V0, Values). 388 389scanl_([], [], _, _, []). 390scanl_([H1|T1], [H2|T2], Goal, V, [VH|VT]) :- 391 call(Goal, H1, H2, V, VH), 392 scanl_(T1, T2, Goal, VH, VT). 393 394 395scanl(Goal, List1, List2, List3, V0, [V0|Values]) :- 396 scanl_(List1, List2, List3, Goal, V0, Values). 397 398scanl_([], [], [], _, _, []). 399scanl_([H1|T1], [H2|T2], [H3|T3], Goal, V, [VH|VT]) :- 400 call(Goal, H1, H2, H3, V, VH), 401 scanl_(T1, T2, T3, Goal, VH, VT). 402 403 404scanl(Goal, List1, List2, List3, List4, V0, [V0|Values]) :- 405 scanl_(List1, List2, List3, List4, Goal, V0, Values). 406 407scanl_([], [], [], [], _, _, []). 408scanl_([H1|T1], [H2|T2], [H3|T3], [H4|T4], Goal, V, [VH|VT]) :- 409 call(Goal, H1, H2, H3, H4, V, VH), 410 scanl_(T1, T2, T3, T4, Goal, VH, VT). 411 412 413 /******************************* 414 * SANDBOX * 415 *******************************/ 416 417:- multifile 418 sandbox:safe_meta_predicate/1. 419 420safe_api(Name/Arity, sandbox:safe_meta_predicate(apply:Name/Arity)). 421 422term_expansion(safe_api, Clauses) :- 423 module_property(apply, exports(API)), 424 maplist(safe_api, API, Clauses). 425 426safe_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.pl
provides compile-time expansion for part of this library.src/Tests/library/test_apply.pl