Search code examples
prologmappingmeta-predicate

Struggling to use Prolog's maplist/2 like a functional mapping function


I'm using SWI-prolog and I'm trying to create a helper-function that will map over a list and multiply each element with a given integer. My intention is to create a predicate that corresponds to the Haskell function multByN x n = x * n and use it in this sense:

map (multByN 3) [1,2,3] which would multiply all elements by 3 and yield [3,6,9]

I searched for the corresponding predicate in Prolog and found maplist/2 however I've only been able to use it to check whether boolean conditions hold for each element in a list rather than actually returning a new, processed list. I understand how this works:

isEven(X) :- 0 is X mod 2

maplist(isEven, [2,4,6]) gives true.

However, I don't understand how one would do something like maplist(multByN(3), [1,2,3]) to actually unify some variable with [3,6,9]. Since I could not figure this out I tried implementing my own mapping function that maps my predicate multByN to a list and I'm getting something that sort of looks right, but that really isn't. I've got this:

multByN(X, N, Y) :- Y is N*X.

mapFunc(_, [], L) :-
    write(L), nl.

mapFunc(N, [H|T], L) :-
    multByN(H, N, Z),
    mapFunc(N, T, [Z|L]).

Using this predicate I get:

?- mapFunc(3, [1,2,3], X).
[9,6,3|_1746]
true ;

Here I'm actually printing the final list to see what it looks like, but we can see that the query doesn't actually say X = [9,6,3|_1746] so I haven't actually unified anything, as far as I'm aware, I've only just printed it - and that's not what I what. Another problem here is the uninstantiated variable _1746 that I want to get rid of, especially since when I try reversing the list I get endless answers and uninstantiated variables.

Ideally, I would like find out both how to solve the problem using maplist/2 and my own predicate, however I would assume others would be more interested in learning how to use maplist/2 and that would be more than enough for me.


Solution

  • In order to make maplist(multByN(3), [1,2,3]) work, you need an extra variable. Thus maplist(multByN(3), [1,2,3], Ys).

    maplist(P_2, Xs, Ys) adds two further arguments one X and one Y to P_2. So multByN(3) needs two extra arguments, like

    multByN(N, X, Y) :-
       Y is N*X.
    
    ?- maplist(multByN(3), [1,2,3], Ys).
       Ys = [3,6,9].
    

    There are some more maplists which roughly correspond to their functional cousins.