I am fairly new to prolog and am trying to mess around with lists of lists. I am curious on how to add two lists of lists or subtract them resulting in one list of list. If I have two lists of lists lets say,
SomeList = [[1,2,3,4],[5,6,7,8]]
SomeList2 = [[1,2,3,4],[5,6,7,8]]
How could I add or subtract SomeList
and SomeList2
to create a list of lists? Resulting in a sum of say
sumList([[2,4,6,8],[10,12,14,16]])
or vice-versa for subtraction? Any help would be appreciated not looking for code but for insight !
The easiest approach is with maplist
:
add(X, Y, Z) :- Z is X + Y.
op_lists(L1, L2, R) :-
maplist(maplist(add), L1, L2, R).
Which gives:
| ?- op_lists([[1,2,3,4],[5,6,7,8]], [[1,2,3,4],[5,6,7,8]], R).
R = [[2,4,6,8],[10,12,14,16]]
yes
| ?-
In the expression:
maplist(maplist(add), L1, L2, R).
maplist(G, L1, L2, R)
calls G
on each element of L1
and L2
, resulting in each element of R
. Since each element of L1
and L2
is a list, then G
in this case is maplist(add)
which calls add
on each element of the sublists.
You can obviously modify add(X, Y, Z)
to be whatever operation you wish on each pair of elements. You can also make the addition more "relational" by using CLP(FD):
add(X, Y, Z) :- Z #= X + Y.
Then you also get, for example:
| ?- op_lists([[1,2,3,4],[5,6,7,8]], L, [[3,6,9,12],[10,12,14,16]]).
L = [[2,4,6,8],[5,6,7,8]]
yes
| ?-
If you wanted to do this without maplist
, you could still use add/3
and use a two-layer approach:
op_lists([], [], []).
op_lists([LX|LXs], [LY|LYs], [LR|LRs]) :-
op_elements(LX, LY, LR),
op_lists(LXs, LYs, LRs).
op_elements([], [], []).
op_elements([X|Xs], [Y|Ys], [R|Rs]) :-
add(X, Y, R),
op_elements(Xs, Ys, Rs).
You can see the simple list processing pattern here, which the use of maplist
takes care of for you.
Besides the solutions presented by @lurker (+1), I would also add the possibility to use DCGs, since you are working on lists. For the available operations I suggest to define a slightly more general predicate opfd/4 instead of add/3. Here are exemplary rules for addition and subtraction as asked in your question, you can use these as templates to add other two-place arithmetic operations:
opfd(+,X,Y,Z) :-
Z #= X+Y.
opfd(-,X,Y,Z) :-
Z #= X-Y.
As the desired operation is an argument, you only need one DCG-rule to cover all operations (marked as (1) at the corresponding goal). This way, of course, you have to specify the desired operation as an argument in your relation and pass it on to the DCGs. The structure of these DCGs is very similar to the last solution presented by @lurker, except that the resulting list does not appear as an argument since that is what the DCGs describe. For easier comparison I will stick with the names op_lists//3 and op_elements//3, the calling predicate shall be called lists_op_results/4:
lists_op_results(L1,L2,Op,Rs) :-
phrase(op_lists(Op,L1,L2),Rs).
op_lists(_Op,[],[]) -->
[].
op_lists(Op,[X|Xs],[Y|Ys]) -->
{phrase(op_elements(Op,X,Y),Rs)},
[Rs],
op_lists(Op,Xs,Ys).
op_elements(_Op,[],[]) -->
[].
op_elements(Op,[X|Xs],[Y|Ys]) -->
{opfd(Op,X,Y,R)}, % <-(1)
[R],
op_elements(Op,Xs,Ys).
Example queries:
?- lists_op_results([[1,2,3,4],[5,6,7,8]], [[1,2,3,4],[5,6,7,8]], +, R).
R = [[2,4,6,8],[10,12,14,16]]
?- lists_op_results([[1,2,3,4],[5,6,7,8]], [[1,2,3,4],[5,6,7,8]], -, R).
R = [[0,0,0,0],[0,0,0,0]]
@lurker's example:
?- lists_op_results([[1,2,3,4],[5,6,7,8]], L, +, [[3,6,9,12],[10,12,14,16]]).
L = [[2,4,6,8],[5,6,7,8]]
You can also ask if there is an operation that fits the given lists:
?- lists_op_results([[1,2,3,4],[5,6,7,8]], L, Op, [[3,6,9,12],[10,12,14,16]]).
L = [[2,4,6,8],[5,6,7,8]],
Op = + ? ;
L = [[-2,-4,-6,-8],[-5,-6,-7,-8]],
Op = -
On a sidenote: Since the operation is the first argument of opfd/4 you can also use it with maplist as suggested in @lurker's first solution. You just have to pass it lacking the last three arguments:
?- maplist(maplist(opfd(Op)),[[1,2,3,4],[5,6,7,8]], L, [[3,6,9,12],[10,12,14,16]]).
L = [[2,4,6,8],[5,6,7,8]],
Op = + ? ;
L = [[-2,-4,-6,-8],[-5,-6,-7,-8]],
Op = -
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With