Ho do I square numbers in a list in prolog?
The list can contain numbers, atoms and lists.
for example: [a,b,2,3,4,[3],[c,d,9]]
and the answer should be [a,b,4,9,16,[3],[c,d,9]]
. As we see in the answer it should be a shallow squaring of the values in the list.
2->4
3->9
4->16
What I have tried so far,
square([],X).
square([A|B],X):-number(A), A is A*A, square(B,X).
X will contain squared values. Base case is when empty list is received. I check if head (A) is a number then I go ahead square the number and change A to A * A. Then go ahead and call the square function for remaining part B.
Please suggest where I am doing wrong.
EDIT: Correct answer as follows. By aBathologist. Please read his comment for detailed explanation.
squared_members([], []).
squared_members([L|Ls], [SqrdL|SqrdLs]) :-
number(L),
SqrdL is L * L,
squared_members(Ls, SqrdLs).
squared_members([L|Ls], [L|SqrdLs]) :-
\+number(L),
squared_members(Ls, SqrdLs).
And
squared_members([], []).
squared_members([L|Ls], [M|Ms]) :-
( number(L)
-> M is L * L, squared_members(Ls, Ms)
; M = L, squared_members(Ls, Ms)
).
We're defining a predicate which describes the relationship between one list, A, and another list, B: B should have all the same elements as A, except that any number in A should be squared in B.
Where you've gone wrong:
square([],X)
, says that when A is empty, then B is anything (so, for instance, even something like square([], 15)
is true). But this doesn't capture the meaning we're after, since the second argument should be a list with the same number of members as the first. That is, when the first list is empty then the second list should be empty. a
(like in your example), number(a)
will be false. Since there are no additional rules for the predicate, it will simply be false unless every member of the first list is a number. <variable> is <expression>
. What you've written says a = a * a which cannot be the case. *What you're definition says is, roughly, this: The list B is a squared version of the list A if A is an empty list and B is anything OR if the first element of A is a number, and that number is equal to itself squared, and B is a squared version of the rest of A.
Here's one possible solution:
squared_members([], []).
squared_members([L|Ls], [SqrdL|SqrdLs]) :-
number(L),
SqrdL is L * L,
squared_members(Ls, SqrdLs).
squared_members([L|Ls], [L|SqrdLs]) :-
\+number(L),
squared_members(Ls, SqrdLs).
Notice that this definition is able to establish a meaningful relationship between the two lists by having them either share variables, or contain elements related by a chain of relations between variables (ie, SqrdL is related to L by virtue of being L * L). This definition has one more clause then yours, which enables it to take account of the members of a list which are not numbers: those are added to the second list unaltered.
An alternative definition, using If-Then-Else notation for cleaner expression, would be the following:
squared_members([], []).
squared_members([L|Ls], [M|Ms]) :-
( number(L)
-> M is L * L, squared_members(Ls, Ms)
; M = L, squared_members(Ls, Ms)
).
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.