Luis Fernando Pineda
Luis Fernando Pineda

Reputation: 91

Prolog multiply all elements of a list

I want to define a predicate in Prolog, prod_list/2 that multiplies every element of a list. I'm having problem with the empty list wish the product should be zero, instead i get false. My code is

prod_list([H], H).
prod_list([H|T], Product) :- prod_list(T, Rest), 
                            Product is H * Rest.

The results I get are prod_list([4,3],Product). -> Product = 12 but when I do prod_list([], Product). I get false instead of Product = 0.

Please help.

Upvotes: 0

Views: 8734

Answers (2)

Renzo
Renzo

Reputation: 27424

Your problem is that no clause matches the empty list. In fact you have a recursive clause:

prod_list([H|T], Product) :- prod_list(T, Rest), 
                        Product is H * Rest.

but its recursion terminates when there is only an element in the list:

prod_list([H], H).

So, in no case the empty list [] is matched by a clause, and for this reason, the answer is false (no match available).

To solve your problem you need to include an explicit clause for the empty list:

prod_list([],0).
prod_list([H],H).
prod_list([H|T], Product) :- prod_list(T, Rest), Product is H * Rest.

A different solution could be found considering that the product of an empty list should be (correctly) defined in this way:

product_of_list([], 1).
product_of_list([H|T], Product) :- product_of_list(T, Rest), Product is H * Rest

then you could add your “special” definition of prod_list:

prod_list([],0).
prod_list(List, Product) :- product_of_list(List, Product).

Edit

The last solution does not work for some interactive versions of Prolog (for instance Swish on-line), while it does work for SWI-Prolog (Multi-threaded, 64 bits, Version 7.3.11). A solutions that should work for every version is the following:

prod_list([],0).
prod_list([H|T], Product) :- product_of_list([H|T], Product).

Thanks to user474491 for discovering this.

Upvotes: 7

Diego Sevilla
Diego Sevilla

Reputation: 29011

Renzo's answer is perfect. I just thought of functional treatment of lists when I saw your question. You can have them just in case you need them. If you define a function multiplication:

mul(V1,V2,R) :- R is V1*V2;

then you can use foldl in any of its variants:

?- foldl(mul, [1,2,10], 1, R).
R = 20 .

fold is a traditional functional calculation function that applies a function accumulating the temporal result.

Upvotes: 4

Related Questions