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