Reputation: 491
so I've been working on the following question:
Write a 3-place predicate scalarMult whose first argument is an integer, whose second argument is a list of integers, and whose third argument is the result of scalar multiplying the second argument by the first. For example, the query
?- scalarMult(3,[2,7,4],Result).
should yield
Result = [6,21,12]
Do this with the help of an accumulator and a wrapper predicate.
This is what I have done:
scalarMult(I, List1, List2):- scalarMult1(I, List1, [], List2).
scalarMult1(I,[], A, A).
scalarMult1(I,[H|T], A, Result):- H1 is H*I, scalarMult1(I,T,[H1|A],Result).
The only trouble with this is that it's putting the new elements at the head of the accumulator so I kind of end up with a reversed list (so for the example above, I would get Result = [12,21,6]). Is there any way I could work around this? I tried using reverse in my code but all my attempts fails.
Thanks
Upvotes: 1
Views: 1041
Reputation: 18663
Noting Carlo's remark about the use of accumulators being for didactical purposes, no accumulator is required for a straight-forward definition of the scalar_multiplication/3
predicate (renamed from scalarMult/3
; camel case is not considered good programming style in Prolog):
% first exchange argument orders to take advantage of the first-argument
% indexing that is provided in most Prolog implementations
scalar_multiplication(Scalar, Numbers, ScaledNumbers) :-
scalar_multiplication_(Numbers, Scalar, ScaledNumbers).
% base case; either input list was empty or we finished traversing the list
scalar_multiplication_([], _, []).
% recursive case
scalar_multiplication_([Number| Numbers], Scalar, [ScaledNumber| ScaledNumbers]) :-
ScaledNumber is Number * Scalar,
scalar_multiplication_(Numbers, Scalar, ScaledNumbers).
This is an instance of a common pattern for processing lists. So common that several Prolog implementations provide a second-order predicate (or meta-predicate), usually named map/3
or maplist/3
, to handle it.
Upvotes: 1
Reputation: 60004
using reverse/2 works, actually:
scalarMult(I, List1, List2):- scalarMult1(I, List1, [], T), reverse(T, List2).
but I think the requirement to use an accumulator (really useless here) could be on purpose to verify your level of lists handling.
Upvotes: 2