My confusion mainly lies around understanding singleton variables.
I want to implement the predicate noDupl/2
in Prolog. This predicate can be used to identify numbers in a list that appear exactly once, i. e., numbers which are no duplicates. The first argument of noDupl
is the list to analyze. The
second argument is the list of numbers which are no duplicates, as described below.
As an example, for the list [2, 0, 3, 2, 1]
the result [0, 3, 1]
is computed (because 2
is a duplicate).
In my implementation I used the predefined member predicate and used an auxiliary predicate called helper.
I'll explain my logic in pseudocode, so you can help me spot where I went wrong.
T
, call the helper method on the rest of the list, the first element H
and the new list.Helper method, if H
is found in the tail, return list without H
, i. e., Tail
.
noDupl([],[]).
noDupl([H|T],L) :-
\+ member(H,T),
noDupl(T,[H|T]).
noDupl([H|T],L) :-
member(H,T),
helper(T,H,L).
helper([],N,[]).
helper([H|T],H,T). %found place of duplicate & return list without it
helper([H|T],N,L) :-
helper(T,N,[H|T1]).%still couldn't locate the place, so add H to the new List as it's not a duplicate
While I'm writing my code, I'm always having trouble with deciding to choose a new variable or use the one defined in the predicate arguments when it comes to free variables specifically. Thanks.
Prolog predicate is the method to contain the argument and return the boolean values such as true or false. It is a function to operate and return given values, variables, or arguments using a prolog programming language.
Goals relating to user-defined predicates are evaluated by examining the database of rules and facts loaded by the user. Prolog attempts to satisfy a goal by matching it with the heads of clauses in the database, working from top to bottom. ?-dog(X). might be matched with the fact dog(fido).
You don't "return" a value of false in Prolog. A predicate fails (results in false ) if it cannot succeed with the given arguments. So the absence of a predicate clause that supports the empty list will automatically fail. Just leave parseList([], N) out of your code.
sqrt(X). Besides these, there are some other predicates such as sin, cos, tan, asin, acos, atan, atan2, sinh, cosh, tanh, asinh, acosh, atanh, log, log10, exp, pi, etc. Now let us see these functions in action using a Prolog program.
Warnings about singleton variables are not the actual problem.
Singleton variables are logical variables that occur once in some Prolog clause (fact or rule). Prolog warns you about these variables if they are named like non-singleton variables, i. e., if their name does not start with a _
.
This convention helps avoid typos of the nasty kind—typos which do not cause syntax errors but do change the meaning.
Let's build a canonical solution to your problem.
First, forget about CamelCase
and pick a proper predicate name that reflects the relational nature of the problem at hand: how about list_uniques/2
?
Then, document cases in which you expect the predicate to give one answer, multiple answers or no answer at all. How? Not as mere text, but as queries.
Start with the most general query:
?- list_uniques(Xs, Ys).
Add some ground queries:
?- list_uniques([], []).
?- list_uniques([1,2,2,1,3,4], [3,4]).
?- list_uniques([a,b,b,a], []).
And add queries containing variables:
?- list_uniques([n,i,x,o,n], Xs).
?- list_uniques([i,s,p,y,i,s,p,y], Xs).
?- list_uniques([A,B], [X,Y]).
?- list_uniques([A,B,C], [D,E]).
?- list_uniques([A,B,C,D], [X]).
Now let's write some code! Based on library(reif)
write:
:- use_module(library(reif)). list_uniques(Xs, Ys) :- list_past_uniques(Xs, [], Ys). list_past_uniques([], _, []). % auxiliary predicate list_past_uniques([X|Xs], Xs0, Ys) :- if_((memberd_t(X,Xs) ; memberd_t(X,Xs0)), Ys = Ys0, Ys = [X|Ys0]), list_past_uniques(Xs, [X|Xs0], Ys0).
What's going on?
list_uniques/2
is built upon the helper predicate list_past_uniques/3
At any point, list_past_uniques/3
keeps track of:
Xs
) and Xs0
) some item of the original list X
.If X
is a member of either list, then Ys
skips X
—it's not unique!
Otherwise, X
is unique and it occurs in Ys
(as its list head).
Let's run some of the above queries using SWI-Prolog 8.0.0:
?- list_uniques(Xs, Ys).
Xs = [], Ys = []
; Xs = [_A], Ys = [_A]
; Xs = [_A,_A], Ys = []
; Xs = [_A,_A,_A], Ys = []
...
?- list_uniques([], []).
true.
?- list_uniques([1,2,2,1,3,4], [3,4]).
true.
?- list_uniques([a,b,b,a], []).
true.
?- list_uniques([1,2,2,1,3,4], Xs).
Xs = [3,4].
?- list_uniques([n,i,x,o,n], Xs).
Xs = [i,x,o].
?- list_uniques([i,s,p,y,i,s,p,y], Xs).
Xs = [].
?- list_uniques([A,B], [X,Y]).
A = X, B = Y, dif(Y,X).
?- list_uniques([A,B,C], [D,E]).
false.
?- list_uniques([A,B,C,D], [X]).
A = B, B = C, D = X, dif(X,C)
; A = B, B = D, C = X, dif(X,D)
; A = C, C = D, B = X, dif(D,X)
; A = X, B = C, C = D, dif(D,X)
; false.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With