简体   繁体   中英

Prolog: square numbers in a list

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:

  • Your ground condition, 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.
  • The same problem occurs with your recursive rule, since, at each iteration, an undetermined variable is passed along, and there is never anything said about the relationship between the first list and the second.
  • This rule will only succeed if the first element of alist is a number. In the case where the first element is, eg, 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.
  • Variables in Prolog must always have the same, consistent value throughout the context in which they appear. They function like variables in arithmetic formula. The formula a + b - b = a is true for any values of a and b but *only if a and b are each assigned one, consistent value throughout the equation. The same is true in Prolog statements of the form <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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM