3
votes

What I have to do is, write a predicate Multiplication/3, whose first argument is an integer, second argument is a list, and the third argument is the result of multiplying the integer with the list, for example:

?-Multiplication(3,[2,7,4],Result).

should return

Result = [6,21,12].

Here's my code:

Multiplication(X,[],Result).

Multiplication(X,[Head|Tail],Result) :-
    Y is X*Head,
    append([Result], [Y], L),
    append([],L,Result),  // HERE
    Multiplication(X,Tail,Result).

And I get the following error:

Domain error: 'acyclic_term ' expected, found '@(lists:append([],S_1,S_1),[S_1=[S_1,1]])'

on the second append call.

If anyone knows why I receive the error, how to fix it or another way to solve this, I'm open to ideas.

3

3 Answers

3
votes

Your two goals append([Result], [Y], L), append([],L,Result) are exactly the same as:

L = [Result,Y], L = Result.

or even simpler:

L = [L,Y]

which would result either in silent failure or an infinite term. Instead, your Prolog produces an error, so that you can correct your program.

2
votes

In your original code:

Multiplication(X,[Head|Tail],Result) :-
    Y is X*Head,
    append([Result], [Y], L),
    append([],L,Result),  // HERE
    Multiplication(X,Tail,Result).

You're getting a "cycle" because you're appending Result to something to get L, then appending something to L to get Result. That's not good. You also have a capitalized predicate name, which is a syntax error. (I assume that, since you ran your code, it wasn't capitalized in the original version.)

You're new proposed solution is overly complicated. Why do you need the 4th argument? Also, your base case for return (which is return(X, [], Result) doesn't make sense, as it has to singleton variables. The use of append/3 is overkill since recursion handles the iteration through the list elements for you.

Starting from the top, you have a common pattern in Prolog where you want to run a query on corresponding elements of two or more lists. A simple recursive solution would look something like this:

multiplication(_, [], []).    % Multiplying anything by the empty list is the empty list
multiplication(M, [X|Xs], [XX|XXs]) :-
    XX is M * X,
    multiplication(M, Xs, XXs).

Another way to implement this kind of pattern in Prolog is with maplist/3. You can first define the query on corresponding elements:

multiply(X, Y, Product) :- Product is X * Y.

Then use maplist/3:

multiplication(M, List, Result) :-
    maplist(multiply(M), List, Result).

Maplist will do a call(multiply(M), ...) on each corresponding pair of elements of List and Result.

0
votes

I edited the code and came up with this:

multiplication(X,[],Result,Result).

multiplication(X,[Head|Tail],List,Result) :-
    Y is X*Head,
    append(List, [Y], L),
    multiplication(X,Tail,L,Result).

return(X,[],Result).

return(X,L,Result) :-
    multiplication(X,L,_,Result).

and the query:

return(2,[1,2],Result).

After the first run, it seems to return Result as it should be, but it runs forever.