Prolog write list function exit condition - list

I'm new to Prolog and am trying to define a simple function that writes a list. So far I have;
printList([Head|Tail]) :-
write(Head), nl,
printList(Tail).
When I call this function like printList([[1,2],[3,4],[5,6]]) it writes:
[1,2]
[3,4]
[5,6]
false
The output above is correct except for the false that shows at the bottom of the list. I assume is shows false because There isn't some kind of exit condition on the printList function to control for when the list is empty. How would I do this? Thanks!

Exactly!!! you need a rule for empty list. Just write:
printList([]).
printList([Head|Tail]) :-
write(Head), nl,
printList(Tail).
Example:
?- printList([[1,2],[3,4],[5,6]]).
[1,2]
[3,4]
[5,6]
true.

Related

Check if list is made up by numbers only - Prolog

I need to write a predicate that returns true if a given list contains only numbers in Prolog. Example:
?- isDigit(['1', '2', '3']).
true
This is the code I've made so far:
isDigit(X) :- digit(X).
isDigit([X | Xs]) :- digit(X), isDigit(Xs).
digit(1).
digit(2).
digit(3).
digit(4).
digit(5).
digit(6).
digit(7).
digit(8).
digit(9).
digit(0).
It returns false every time and i don't get the reason why.
Thank you
I found two issues with your code. First:
isDigit(X) :- digit(X).
In your case the argument of isDigit/1 is a list, and you want to ask for the elements of this list. For handling the only element of a list write it like this:
isDigit([X]) :- digit(X).
Second: 1 and '1' are different. Try this as query:
?- isDigit([1, 2, 3]).
Tested with SWISH.

Splitting a list of integers into two sublists with the same sum, Prolog

the query is successful when a list of integers is split into two sublists and both the sublists sum to the same value
an example of a successful query would be:
split([1,1,1,3]).
or
split([15,1,2,3,4,5]).
an unsuccessful would be something like
split([1,2,10]).
When I'm working on relations between integers, I often use clpfd.
:- use_module(library(clpfd)).
Sublists are contiguous subsequences.
"Exactly two sublists" implies "prefix / suffix".
Using append/3 and sum/3 define split/1:
split(Xs) :-
append(Prefix, Suffix, Xs),
sum(Prefix, #=, Sum),
sum(Suffix, #=, Sum).
Sample queries with SWI-Prolog 8.0.0:
?- split([1,1,1,3]).
true ;
false.
?- split([15,1,2,3,4,5]).
true ;
false.
?- split([1,2,10]).
false
Two queries succeed1, one fails. Like you said they should.
Footnote 1: Don't worry about getting answers like true ; false.—this is how the prolog-toplevel indicates that Prolog did some backtracking search.

A predicate that checks the output of another predicate?

I have a predicate which checks for duplicates in a list and returns true if there are no duplicates and false if there are duplicates present:
removeDups([], []).
removeDups([H|T], [H|T1]) :- subtract(T, [H], T2), removeDups(T2, T1).
I want to write another predicate that will basically check if removeDups successfully removes duplicates from a list whilst leaving the other list items present still. So for example a predicate testRemoveDuplicates/1 where the input is a list. I'm not sure how to go about doing this though.
Thanks in advance.
remove_dups(+List, ?Pruned) Sicstus
removes duplicated elements from List, which should be a proper list.
test
| ?- remove_dups([item0,item1,item0,item2,item3,item4,item2], Pruned).
Pruned = [item0,item1,item2,item3,item4] ? ;
no
% source_info
| ?- remove_dups([item0,item1,item0,item2,item3,item4,item2], [item0,item1,item2,item3,item4]).
yes
if you want to integrate your predicat then
testRemoveDuplicates(ListResult) :- removeDups(ListResult,ListResult).

Sublists in Prolog(without recognizing the empty list)

I want to create a predicate in Prolog which will check if a list A is a sublist of a list B. Moreover I do not want my program to consider an empty list as a subset of another one.
E.g. included_list([1,4],[1,2,3,4,5]).
true.
included_list([2,3],[1,2,3,4,5]).
true.
included_list([1,6],[1,2,3,4,5]).
false.
included_list([],[1,2,3,4,5]).
false.
and so on...
So, I have written the following code so far:
member(X,[X|Tail]).
member(X,[Head|Tail]):- member(X,Tail).
included_list([X],_).
included_list([Head|Tail],List):- member(Head,List), included_list(Tail,List).
But the above code seems to be wrong, because in one specific case it throws true, instead of throwing wrong. I wish I'd made it clear having presented the following screenshot:
As you might have noticed the fifth(5th) sentence gives true, instead of wrong. That is, when I write a sentence of the form:
included_list([x,y],[w,x,v,z]).
whereas only x is included in the second list(and not y) the program gives me true(and this is wrong).
In general, if the first argument of the first list is included in the second list then, no matter if the rest of the former are included in the latter, the program gives me true.
In any other case the program gives me the right result(true or false).
What do I do wrong?
I will be waiting for your answers!
Thank you in advance!
Your problem is the first clause of included_list/2. This:
included_list([X], _).
What does it mean? It means, "If the first argument is a list with one element, succeed, ignoring the second argument."
A short aside: if you would not ignore compiler warnings, you would have caught this mistake already. You should get a loud and clear "Singleton variable" warning, hinting that the code you have written does not do what you think it does.
What you actually mean is more along the lines of:
subset_list([X|Xs], Ys) :-
subset_list_1(Xs, X, Ys).
subset_list_1([], X, Ys) :-
member(X, Ys).
subset_list_1([X|Xs], X0, Ys) :-
member(X0, Ys),
subset_list_1(Xs, X, Ys).
But I don't know why you don't simply use the available subset/2, and simply add a requirement that the subset is not an empty list:
subset_list(Subset, List) :-
Subset = [_|_], % a list with at least one element
subset(Subset, List).
Despite what the documentation claims, the second argument to subset/2 does not have to be a true "set", but it does expect that both lists are ground (do not contain any free variables). You can see the source code here.
In this answer we let meta-predicate maplist/2 handle recursion and define:
all_included(Sub, Es) :-
same_length(Es, Xs),
Sub = [_|_], % minimum length: 1
append(_, Sub, Xs), % maximum length: as long as `Es`
maplist(list_member(Es), Sub).
Let's run the queries the OP gave!
First up, use-cases we expect to succeed:
?- member(Xs, [[1,4],[2,3],[2,3,5],[3,4]]), all_included(Xs, [1,2,3,4,5]).
Xs = [1,4]
; Xs = [2,3]
; Xs = [2,3,5]
; Xs = [3,4]
; false.
Next up, some use-cases we expect to fail:
?- member(Xs, [[],[2,6],[1,6]]), all_included(Xs, [1,2,3,4,5]).
false.
?- all_included([3,5], [1,2,5]).
false.

How can I check if an element in the list is an empty list: []?

How can I check if an element in the list is an empty list: [] ?
I've got the following:
display_degrees([A,B,C,D]):- write(B).
display_degrees([A,B,C,D]):- B==[], nl,write('has no degree'), nl, !.
When I enter in something like:
display_degrees([1,[],3,4]).
I just get: [] instead of 'has no degree'. Is my syntax wrong? Can I not add a clause to this predicate like this?
You're getting this behavior because proof search stops when a goal has succeeded. When you type
display_degrees([1,[],3,4]).
the first rule unifies, and it writes B. Since it was a success, it stops. You can ask Prolog to keep searching, and then it will find the second clause. In swipl, I get
?- [foo].
?- display_degrees([1,[],3,4]).
[]
true r % I type 'r' there
has no degree
true.
If you're just learning Prolog, I suggest you avoid the cut operator ! for some time. Also, doing IO is not the most intuitive thing. I would try some exercises with defining things like natural numbers and recursive functions. E.g., plus:
plus(z, X, X).
plus(s(X), Y, s(Z)) :- plus(X, Y, Z).
The problem with what you have is that the more general rule will fire first. You could switch the order:
display_degrees([A,[],C,D]) :- nl, write('has no degree'), nl, !.
display_degrees([A,B,C,D]) :- write(B).
I could just as well have written for the first predicate:
display_degrees([A,B,C,D]) :- B == [], nl, write('has no degree'), nl, !.
But the "shortcut" I show initially is more idiomatic for a Prolog predicate like this.
I kept the cut since you know you deterministically want one choice. The first rule will match if and only if the second list element is [].
| ?- display_degrees([1,[],3,4]).
has no degree
yes
| ?- display_degrees([1,2,3,4]).
2
yes
| ?-