Prolog List Squaring, Modifying element in List - prolog

I am trying to write a short Prolog program which takes a list of numbers and returns a list where all numbers have been squared.
Ie: [2,4,5] => [4,16,25]
My code so far:
list_of_squares([X], L) :-
L is X^2.
list_of_squares([X|XS], [X^2|M]) :-
list_of_squares(XS, M).
For some reason though Prolog doesn't like me squaring X while adding it to a list... Any thoughts on how I could do this?

You're not that far off, but you make two small mistakes:
Firstly, you mix element X with list L. Your first clause should be:
list_of_squares([X], [Y]):-
Y is X ^ 2.
Secondly, you cannot perform an arithmetic function in list notation.
Your second clauses should be as follows:
list_of_squares([X|Xs], [Y|Ys]):-
Y is X ^ 2,
list_of_squares(Xs, Ys).
Thirdly, there is a more fundamental problem. With the first two fixes, your code works, but the base case, i.e. the first clause, is not that well chosen. (A) the code cannot process the empty list. (B) For a singleton list the code is needlessly nondeterministic, because both clauses apply. This is solved by choosing the base case wisely:
squares([], []).
squares([X|Xs], [Y|Ys]):-
Y is X ^ 2,
squares(Xs, Ys).

Here is a general method how you can localize such an error. First, let's start with your exemple:
?- list_of_squares([2,4,5],[4,16,25]).
false.
Oh no! It fails! There is a very general method what to do in such a situation:
Generalize the query
So we replace [4,16,25] by a new, fresh (ah, true freshness!) variable:
?- list_of_squares([2,4,5],L).
L = [2^2,4^2|25]
; false.
That's way better: Now you know that there is a "result", but that result it not what you expected.
Next,
Minimize the query
The list is way too long, so I will chop off some elements. Say, the first two:
?- list_of_squares([5],L).
L = 25
; false.
Again, wrong, but smaller. Now, where is the error for that? To get it
Specialize your program
list_of_squares([X], L) :-
L is X^2.
list_of_squares([X|XS], [X^2|M]) :- false,
list_of_squares(XS, M).
That program, again gives the same wrong answer! So in there is a bug in the visible part. What we expect is
?- list_of_squares([5],[25]).
false.
this to succeed. But where is the error? Again:
Generalize the query
?- list_of_squares([5],[X]).
false.
HET!
Now, you should realize that that rule might be:
list_of_squares([X], [Y]):-
Y is X ^ 2.
And the same (is)/2 should be used in the recursive rule. And, why not accept [].
I, personally, would rather write using library(lambda):
list_of_squares(Xs, Ys) :-
maplist(\X^XX^(XX is X^2), Xs, Ys).
Or, even better, using library(clpfd)
list_of_squares(Xs, Ys) :-
maplist(\X^XX^(XX #= X^2), Xs, Ys).

Prolog doesn't have a 'functional' mindset, but some standard builtin predicate can help working with lists. In this case
list_of_squares(L,S) :- findall(Sq,(member(E,L),Sq is E*E),S).
?- list_of_squares([2,4,5], R).
R = [4, 16, 25].
in this case, member/2 play a role similar to lambda expressions, giving a 'name' to each element E available in L. findall/3 compute all solutions of its goal ,(member(E,L),Sq is E*E),, and collects results (the 'template' expression, that is, Sq).

Related

Non-termination of common reverse/2 implementation, and better solutions?

The following is a standard textbook definition of reverse(X,Y) which is true if the list Y is the reverse of the list X. The code is often used to introduce or illustrate the use of an accumulator.
% recursive definition
step([], L2, L2).
step([H1|T1], X, L2) :- step(T1, X, [H1|L2]).
% convenience property around step/3
reverse(X, Y) :- step(X, Y, []).
The following query works as expcted.
?- reverse([1,2,3], Y).
Y = [3,2,1]
But the following fails after it prompts to search for more solutions after the first one.
?- reverse(X, [1,2,3]).
X = [3,2,1]
Stack limit (0.2Gb) exceeded
Stack sizes: local: 3Kb, global: 0.2Gb, trail: 0Kb
Stack depth: 4,463,497, last-call: 100%, Choice points: 12
...
Questions:
What is the choice point prolog is going back to?
Is this called non-termination? I am not familiar with prolog terminology.
Is there a better way to define reverse(X,Y) such that it is reversible, in the sense that both of the above queries work and terminate?
I have found that using a cut step([], L2, L2):- !. appears to work, but this seems like we've waded into procedural programming and have drifted far away from declarative logic programming. Is this a fair judgement?
1mo, frankly I do not know what kind of choicepoint is responsible. This is a notion far too low level to be of direct relevance. And there are better techniques to understand the problem, in particular failure slices.
2do, the problem here is called (universal) non-termination. But note how you found it: You got an answer and then only when demanding the next answer Prolog looped. This can be even worse, like looping only after the n-th answer. The easiest way to spot all kinds of non-termination is to just add false to the query. If G_0 terminates universally also G_0, false terminates (and fails).
3tio, yes there is. But first, try to understand why your original program looped. The best is to add some falsework into your program. By adding goals false we obtain a failure-slice. And if we find such a slice that already does not terminate then also the original program does not terminate. (No further analysis required!1) Here is the one of relevance:
step([], L2, L2) :- false.
step([H1|T1], X, L2) :- step(T1, X, [H1|L2]), false.
reverse(X, Y) :- step(X, Y, []), false.
?- reverse(X, [1,2,3]), false.
loops.
So we need to understand only that visible part! As promised, there is now not a single choicepoint present.
Just look at the head of step/3! There, only the first argument insists on some specific term, but the second and third do not insist on anything. Therefore the second and third argument cannot influence termination. They are termination neutral. And thus, only the first argument of reverse/2 will influence termination.
To fix this, we need to somehow get the second argument of reverse/2 into a relevant position in step. The simplest way is to add another argument. And, if we are at it, we may realize that both arguments of reverse/2 are of the same length, thus:
step([], L2, L2, []).
step([H1|T1], X, L2, [_|Y]) :- step(T1, X, [H1|L2], Y).
reverse(X, Y) :- step(X, Y, [], Y).
?- reverse(X, [1,2,3]), false.
false.
?- reverse([1,2,3], Y), false.
false.
?- reverse(X,Y).
X = [], Y = []
; X = [_A], Y = [_A]
; X = [_A,_B], Y = [_B,_A]
; X = [_A,_B,_C], Y = [_C,_B,_A]
; ... .
4to, don't believe the tale of the green cut! They are so rare. Most good cuts are placed together with a guard that ensures that the cut is safe. See how your cut wreaked havoc:
?- X = [a], reverse(X,Y).
X = "a", Y = "a". % nice
?- reverse(X,Y), X = [a].
false, unexpected.
?- reverse(L,[]).
L = [].
?- L = [_|_], reverse(L,[]).
loops, unexpected.
So sometimes the program will fail incorrectly, and the looping is still present. Hardly an improvement.
1 Assuming that we use the pure monotonic subset of Prolog
Yes, you have correctly noted that this predicate does not terminate when you pass a variable in the first argument. It also does not terminate if the first argument is a partial list.
The first witness that you reported comes from the fact step([], L2, L2)., which is clearly the base case for your recursion/induction. When you ask the Prolog engine for additional witnesses, it proceeds by trying to do so using the induction rule step([H1|T1], X, L2) :- step(T1, X, [H1|L2]). Note that your implementation here is defined recursively on the first argument, and so this unifies the unbound first argument with [H1|T1], and then makes a recursive call with T1 as the first argument, which then unifies with a fresh [H1|T1], which makes a recursive call... This is the cause of the infinite loop you're observing.
Yes.
Often times with nontermination issues, it's helpful to understand Prolog's execution model. That doesn't necessarily mean we can't come up with a "pure logic" solution, though. In this case, the query doesn't terminate if the first argument is a partial list, so we simply need to ensure that the first argument has a fixed length. What should its length be? Well, since we're reversing a list it should be the same as the other list. Try out this definition instead:
reverse(X, Y) :- same_length(X, Y), step(X, Y, []).
This solves the problem for both of the queries you posed. As an added bonus, it's actually possible to pose the "most general query" and get a sensible infinite sequence of results with this definition:
?- reverse(X, Y).
X = Y, Y = [] ;
X = Y, Y = [_] ;
X = [_A, _B],
Y = [_B, _A] ;
X = [_A, _B, _C],
Y = [_C, _B, _A] ;
X = [_A, _B, _C, _D],
Y = [_D, _C, _B, _A] ;
...
As far as I know, there isn't really a clear way to describe Prolog's cut operator in the language of first order logic. All of the literature I've read on the topic describe it operationally within the context of Prolog's execution model — by this I mean that its semantics are defined in terms of choice points/backtracking rather than propositions and logical connectives. That being said, it's hard to write Prolog code that is fast or has good termination properties without being aware of the execution model, and "practical" Prolog programs often use it for this reason (look up "Prolog red and green cuts"). I think your judgement that the cut is "procedural" is on the right track, but personally I think it's still a valuable tool when used appropriately.
swi-prolog added an extra argument to fix such termination:
?- reverse(L, [1,2,3]).
L = [3,2,1].

Prolog Program Not Merging Sorted Lists Correctly

I have a simple program I'm trying to write in Prolog. Essentially, as I learning exercise, I'm trying to write a program that takes two sorted lists as input, and returns the merged list that is also sorted. I have dubbed the predicate "merge2" as to no be confused with the included predicate "merge" that seems to do this already.
I am using recursion. My implementation is below
merge2([],[],[]).
merge2([X],[],[X]).
merge2([],[Y],[Y]).
merge2([X|List1],[Y|List2],[X|List]):- X =< Y,merge2(List1,[Y|List2],List).
merge2([X|List1],[Y|List2],[Y|List]):- merge2([X|List1],List2,List).
When I run this, I get X = [1,2,4,5,3,6] which is obviously incorrect. I've been able to code multiple times and tried to draw out the recursion. To the best of my knowledge, this should be returning the correct result. I'm not sure why the actualy result is so strange.
Thank you.
QuickCheck is your friend. In this case, the property that you want to verify can be expressed using the following predicate:
sorted(L1, L2) :-
sort(L1, S1),
sort(L2, S2),
merge2(S1, S2, L),
sort(L, S),
L == S.
Note that sort/2 is a standard Prolog built-in predicate. Using the QuickCheck implementation provided by Logtalk's lgtunit tool, which you can run using most Prolog systems, we get:
?- lgtunit::quick_check(sorted(+list(integer),+list(integer))).
* quick check test failure (at test 2 after 0 shrinks):
* sorted([0],[0])
false.
I.e. you code fails for L1 = [0] and L2 = [0]:
?- merge2([0], [0], L).
L = [0, 0] ;
L = [0, 0] ;
false.
Tracing this specific query should allow you to quickly find at least one of the bugs in your merge2/4 predicate definition. In most Prolog systems, you can simply type:
?- trace, merge2([0], [0], L).
If you want to keep duplicates in the merged list, you can use the de facto standard predicates msort/2 in the definition of the property:
sorted(L1, L2) :-
sort(L1, S1),
sort(L2, S2),
merge2(S1, S2, L),
msort(L, S),
L == S.
In this case, running QuickCheck again:
?- lgtunit::quick_check(sorted(+list(integer),+list(integer))).
* quick check test failure (at test 3 after 8 shrinks):
* sorted([],[475,768,402])
false.
This failure is more informative if you compare the query with your clauses that handle the case where the first list is empty...
This is done using difference list and since you are learning it uses reveals, AKA spoiler, which are the empty boxes that you have to mouse over to ravel the contents. Note that the reveals don't allow for nice formatting of code. At the end is the final version of the code with nice formatting but not hidden by a reveal so don't peek at the visible code at the very end if you want to try it for yourself.
This answer takes it that you have read my Difference List wiki.
Your basic idea was sound and the basis for this answer using difference list. So obviously the big change is to just change from closed list to open list.
As your code is recursive, the base case can be used to set up the pattern for the rest of the clauses in the predicate.
Your simplest base case is
merge2([],[],[]).
but a predicate using difference list can use various means to represent a difference list with the use of L-H being very common but not one I chose to use. Instead this answer will follow the pattern in the wiki of using two variables, the first for the open list and the second for the hole at the end of the open list.
Try to create the simple base case on your own.
merge2_prime([],[],Hole,Hole).
Next is needed the two base cases when one of the list is empty.
merge2_prime([X],[],Hole0,Hole) :-
Hole0 = [X|Hole].
merge2_prime([],[Y],Hole0,Hole) :-
Hole0 = [Y|Hole].
Then the cases that select an item from one or the other list.
merge2_prime([X|List1],[Y|List2],Hole0,Hole) :-
X =< Y,
Hole0 = [X|Hole1],
merge2_prime(List1,[Y|List2],Hole1,Hole).
merge2_prime(List1,[Y|List2],Hole0,Hole) :-
Hole0 = [Y|Hole1],
merge2_prime(List1,List2,Hole1,Hole).
Lastly a helper predicate is needed so that the query merge2(L1,L2,L3) can be used.
merge2(L1,L2,L3) :-
merge2_prime(L1,L2,Hole0,Hole),
Hole = [],
L3 = Hole0.
If you run the code as listed it will produce multiple answer because of backtracking. A few cuts will solve the problem.
merge2(L1,L2,L3) :-
merge2_prime(L1,L2,Hole0,Hole),
Hole = [],
L3 = Hole0.
merge2_prime([],[],Hole,Hole) :- !.
merge2_prime([X],[],Hole0,Hole) :-
!,
Hole0 = [X|Hole].
merge2_prime([],[Y],Hole0,Hole) :-
!,
Hole0 = [Y|Hole].
merge2_prime([X|List1],[Y|List2],Hole0,Hole) :-
X =< Y,
!,
Hole0 = [X|Hole1],
merge2_prime(List1,[Y|List2],Hole1,Hole).
merge2_prime(List1,[Y|List2],Hole0,Hole) :-
Hole0 = [Y|Hole1],
merge2_prime(List1,List2,Hole1,Hole).
Example run:
?- merge2([1,3,4],[2,5,6],L).
L = [1, 2, 3, 4, 5, 6].
?- merge2([0],[0],L).
L = [0, 0].
I didn't check this with lots of examples as this was just to demonstrate that an answer can be found using difference list.

Prolog, understanding append/3

?- append([], [X1], [a,b]).
Why does this return no and not
X1 = a,b
Since
? - append([], [a,b], [a,b])
returns yes?
To understand a Prolog program you have two choices:
Think about the program as you do this in other programming languages by simulating the moves of the processor. This will lead to your mental exasperation very soon unless your name is Ryzen or in other words:
You are a processor
Let Prolog do the thinking and use Prolog to understand programs.
Whenever you see a failing goal, narrow down the reason why the goal fails by generalizing that goal (by replacing some term by a variable). You do not need to understand the precise definition at all. It suffices to try things out. In the case of your query
?- append([], [X1], [a,b]).
false.
We have three arguments. Maybe the first is the culprit? So I will replace it by a new variable:
?- append(Xs, [X1], [a,b]).
Xs = [a], X1 = b
; false.
Nailed it! Changing the first argument will lead to success. But what about the second argument?
?- append([], Ys, [a,b]).
Ys = [a, b].
Again, culprit, too. And now for the third:
?- append([], [X1], Zs).
Zs = [X1].
Verdict: All three kind-of guilty. That is, it suffices to blame one of them. Which one is up to you to choose.
Do this whenever you encounter a failing goal. It will help you gain the relational view that makes Prolog such a special language.
And if we are at it. It often helps to consider maximal failing generalizations. That is, generalizations that still fail but where each further step leads to success. In your example this is:
?- append([], [X1], [a,b]). % original query
false.
?- append([], [_], [_,_|_]). % maximal failing generalization
false.
From this you can already draw some conclusions:
The lists' elements are irrelevant.
Only the length of the three lists is of relevance
The third list needs to be two elements or longer.
See: append/3
append(?List1, ?List2, ?List1AndList2)
List1AndList2 is the concatenation of List1 and List2
So for
?- append([], [X1], [a,b]).
[] is the empty list and [X1] is a list with a variable X1
If you run the query like this
?- append([],[X1],A).
you get
A = [X1].
which means that A is the concatenation of [] and [X1].
In your query it is asking if the concatenation of [] and [X1] is [a,b] which is false, or no.
For your second query
? - append([], [a,b], [a,b])
it is asking if the concatenation of [] and [a,b] is [a,b] which is true, or yes.

How to improve this code that looks for a specific number in a list?

I'm writing prolog code that finds a certain number; a number is the right number if it's between 0 and 9 and not present in a given list. To do this I wrote a predicate number/3 that has the possible numbers as the first argument, the list in which the Rightnumber cannot be present and the mystery RightNumber as third argument:
number([XH|XT], [H|T], RightNumber):-
member(XH, [H|T]), !,
number(XT, [H|T], RightNumber).
number([XH|_], [H|T], XH):-
\+ member(XH, [H|T]).
so this code basically says that if the Head of the possible numbers list is already a member of the second list, to cut of the head and continue in recursion with the tail.
If the element is not present in the second list, the second clause triggers and tells prolog that that number is the RightNumber. It's okay that it only gives the first number that is possible, that's how I want to use it.
This code works in theory, but I was wondering if there's a better way to write it down? I'm using this predicate in another predicate later on in my code and it doesn't work as part of that. I think it's only reading the first clause, not the second and fails as a result.
Does anybody have an idea that might improve my code?
sample queries:
?- number([0,1,2,3,4,5,6,7,8,9], [1,2], X).
X = 3
?- number([0,1,2,3,4,5,6,7,8,9], [1,2,3,4,5,6,7,8,0], X).
X = 9
First, the code does not work. Consider:
?- number(Xs, Ys, N).
nontermination
This is obviously bad: For this so-called most general query, we expect to obtain answers, but Prolog does not give us any answer with this program!
So, I first suggest you eliminate all impurities from your program, and focus on a clean declarative description of what you want.
I give you a start:
good_number(N, Ls) :-
N in 0..9,
maplist(#\=(N), Ls).
This states that the relation is true if N is between 0 and 9, and N is different from any integer in Ls. See clpfd for more information about CLP(FD) constraints.
Importantly, this works in all directions. For example:
?- good_number(4, [1,2,3]).
true.
?- good_number(11, [1,2,3]).
false.
?- good_number(N, [1,2,3]).
N in 0\/4..9.
And also in the most general case:
?- good_number(N, Ls).
Ls = [],
N in 0..9 ;
Ls = [_2540],
N in 0..9,
N#\=_2540 ;
Ls = [_2750, _2756],
N in 0..9,
N#\=_2756,
N#\=_2750 .
This, with only two lines of code, we have implemented a very general relation.
Also see logical-purity for more information.
First of all, your predicate does not work, nor does it check all the required constraints (between 0 and 9 for instance).
Several things:
you unpack the second list [H|T], but you re-pack it when you call member(XH, [H|T]); instead you can use a list L (this however slightly alters the semantics of the predicate, but is more accurate towards the description);
you check twice member/2ship;
you do not check whether the value is a number between 0 and 9 (and an integer anyway).
A better approach is to construct a simple clause:
number(Ns, L, Number) :-
member(Number, Ns),
integer(Number),
0 =< Number,
Number =< 9,
\+ member(Number, L).
A problem that remains is that Number can be a variable. In that case integer(Number) will fail. In logic we would however expect that Prolog unifies it with a number. We can achieve this by using the between/3 predicate:
number(Ns, L, Number) :-
member(Number, Ns),
between(0, 9, Number),
\+ member(Number, L).
We can also use the Constraint Logic Programming over Finite Domains library and use the in/2 predicate:
:- use_module(library(clpfd)).
number(Ns, L, Number) :-
member(Number, Ns),
Number in 0..9,
\+ member(Number, L).
There are still other things that can go wrong. For instance we check non-membership with \+ member(Number, L). but in case L is not grounded, this will fail, instead of suggesting lists where none of the elements is equal to Number, we can use the meta-predicate maplist to construct lists and then call a predicate over every element. The predicate we want to call over every element is that that element is not equal to Number, so we can use:
:- use_module(library(clpfd)).
number(Ns, L, Number) :-
member(Number, Ns),
Number in 0..9,
maplist(#\=(Number), L).

prolog generate list of numbers from a list[x,y]

Hello I want to generate a list as following. Given a list like [x,y] I want to generate a list that is x,x,...,x : y times eg [2,3]=[2,2,2] but I cannot figure out how.
This is my implementation so far:
generate([T,1],[T]).
generate([X,S],[X|T]):-S1 is S-1,generate([X,S1],[T]).
but for some reason it fails. Can you help me?
generate([E,R], Es) :-
length(Es, R),
maplist(=(E), Es).
You said that your version fails. But in fact it does not:
?- generate([a,0], Xs).
false.
?- generate([a,1], Xs).
Xs = [a]
; false.
?- generate([a,2], Xs).
Xs = [a|a]
; false.
?- generate([a,3], Xs).
false.
It doesn't work for 0, seems to work for length 1, then, produces an incorrect solution Xs = [a|a] for length 2, and finally fails from length 3 on. [a|a] is a good hint that at someplace in your definition, lists and their elements are confused. To better distinguish them, use a variable in plural for a list, like Es which is the plural of E.
The problem is in your second clause. When you have [X|T], it means that T is a list. In the body you write generate([X,S1],[T]): by writing [T] you're now saying the second argument to generate is a list of which the only element is this list T. What you want to say is that it is simply this list T:
generate([T,1], [T]).
generate([X,S], [X|T]) :- S1 is S-1, generate([X,S1], T).

Resources