40

How do you write a Prolog procedure map(List, PredName, Result) that applies the predicate PredName(Arg, Res) to the elements of List, and returns the result in the list Result?

For example:

test(N,R) :- R is N*N.

?- map([3,5,-2], test, L).
L = [9,25,4] ;
no
Will Ness
  • 70,110
  • 9
  • 98
  • 181
General_9
  • 2,249
  • 4
  • 28
  • 46

1 Answers1

53

This is usually called maplist/3 and is part of the Prolog prologue. Note the different argument order!

:- meta_predicate(maplist(2, ?, ?)).

maplist(_C_2, [], []).
maplist( C_2, [X|Xs], [Y|Ys]) :-
   call(C_2, X, Y),
   maplist( C_2, Xs, Ys).

The different argument order permits you to easily nest several maplist-goals.

?- maplist(maplist(test),[[1,2],[3,4]],Rss).
   Rss = [[1,4],[9,16]].

maplist comes in different arities and corresponds to the following constructs in functional languages, but requires that all lists are of same length. Note that Prolog does not have the asymmetry between zip/zipWith and unzip. A goal maplist(C_3, Xs, Ys, Zs) subsumes both and even offers more general uses.

  • maplist/2 corresponds to all
  • maplist/3 corresponds to map
  • maplist/4 corresponds to zipWith but also unzip
  • maplist/5 corresponds to zipWith3 and unzip3
  • ...
false
  • 10,264
  • 13
  • 101
  • 209
  • 12
    +1. In modern Prologs, you'll find `maplist` somewhere in the library. – Fred Foo Jul 13 '11 at 19:37
  • 3
    @DavidTonhofer: Please refer to [tag:meta-predicate] for more! – false Nov 21 '14 at 10:16
  • 1
    I do not believe that the SWI-Prolog version of maplist/3 corresponds to map anymore. It seems to be `all` but delivers the input in pairs from both lists. Is there a predicate that has the same functionality as `map`? – bennyty Dec 02 '16 at 02:41
  • SWI has `maplist/2/3/4/5`. And, no SWI **does not** "deliver input in pairs", except you use such a predicate in the 1st argument. Please give a **concrete** example, where you think map cannot be expressed with `maplist`. Except for cases where the lists are of different length. – false Dec 02 '16 at 13:34
  • 3
    Perhaps I am confused by the documentation. [maplist/3](http://www.swi-prolog.org/pldoc/doc_for?object=maplist/3), "As maplist/2, operating on pairs of elements from two lists" implies to me (a novice prolog programmer) that `maplist/3` has the same functionality as `maplist/2` which is `all` but with different inputs to the first argument. This resulted in me ignoring maplist/3 and finding/writing my own map predicate. – bennyty Dec 02 '16 at 19:54
  • 2
    @bennyty: That documentation is infact a bit misleading. – false Dec 03 '16 at 00:12
  • @false I came to the same conclusion. could you explain how `maplist/3` is _not_ `all`? I get: `?- maplist(=, [1, 2, 3], [1, 2, 3]). true.` not `[true, true, true]`, whereas `convlist/3` seems to be exactly `map`. – Erik Kaplun Sep 11 '20 at 20:16
  • 1
    @ErikKaplun: Consider `As = [1,2,3], maplist(`[`succ`](http://www.complang.tuwien.ac.at/ulrich/iso-prolog/prologue#succ)`, As, Bs)`. Where do you see an `all` in here? That's a typical `map`. – false Sep 12 '20 at 13:54
  • 1
    @ErikKaplun: Now you talk about `maplist/2` instead of `maplist/3`. See above... – false Sep 13 '20 at 18:54
  • Oh yeah, that's right, how embarrassing! Apologies, my Prolog-eye is still young! But then I should add that `maplist/3` is also `all`, but can be used like `map`, or even better, `map` and `all` are the same thing in Prolog, due to predicates/relations being more general than functions. – Erik Kaplun Sep 14 '20 at 14:21