Related
I have a predicate to check if the element is member of list and looks the following:
member(X,[X|_]).
member(X,[_|T]) :- member(X,T).
When I called: ?- member(1,[2,3,1,4])
I get: true.
And now I have to use it to write predicate which will remove all non unique elements from list of lists like the following:
remove([[a,m,t,a],[k,a,w],[i,k,b,b],[z,m,m,c]],X).
X = [[t],[w],[i,b,b],[z,c]]
How can I do that?
Using library(reif) for
SICStus|SWI:
lists_uniques(Xss, Yss) :-
maplist(tfilter(in_unique_t(Xss)), Xss, Yss).
in_unique_t(Xss, E, T) :-
tfilter(memberd_t(E), Xss, [_|Rs]),
=(Rs, [], T).
Remark that while there is no restriction how to name a predicate, a non-relational, imperative name often hides the pure relation behind. remove is a real imperative, but we only want a relation. A relation between a list of lists and a list of lists with only unique elements.
An example usage:
?- lists_uniques([[X,b],[b]], [[X],[]]).
dif(X, b).
So in this case we have left X an uninstantiated variable. Therefore, Prolog computes the most general answer possible, figuring out what X has to look like.
(Note that the answer you have accepted incorrectly fails in this case)
Going by your example and #false's comment, the actual problem seems to be something like removing elements from each sublist that occur in any other sublist. My difficulty conceptualizing this into words has led me to build what I consider a pretty messy and gross piece of code.
So first I want a little helper predicate to sort of move member/2 up to lists of sublists.
in_sublist(X, [Sublist|_]) :- member(X, Sublist).
in_sublist(X, [_|Sublists]) :- in_sublist(X, Sublists).
This is no great piece of work, and in truth I feel like it should be inlined somehow because I just can't see myself ever wanting to use this on its own.
Now, my initial solution wasn't correct and looked like this:
remove([Sub1|Subs], [Res1|Result]) :-
findall(X, (member(X, Sub1), \+ in_sublist(X, Subs)), Res1),
remove(Subs, Result).
remove([], []).
You can see the sort of theme I'm going for here though: let's use findall/3 to enumerate the elements of the sublist in here and then we can filter out the ones that occur in the other lists. This doesn't quite do the trick, the output looks like this.
?- remove([[a,m,t,a],[k,a,w],[i,k,b,b],[z,m,m,c]], R).
R = [[t], [a, w], [i, k, b, b], [z, m, m, c]].
So, it starts off looking OK with [t] but then loses the plot with [a,w] because there is not visibility into the input [a,m,t,a] when we get to the first recursive call. There are several ways we could deal with it; a clever one would probably be to form a sort of zipper, where we have the preceding elements of the list and the succeeding ones together. Another approach would be to remove the elements in this list from all the succeeding lists before the recursive call. I went for a "simpler" solution which is messier and harder to read but took less time. I would strongly recommend you investigate the other options for readability.
remove(In, Out) :- remove(In, Out, []).
remove([Sub1|Subs], [Res1|Result], Seen) :-
findall(X, (member(X, Sub1),
\+ member(X, Seen),
\+ in_sublist(X, Subs)), Res1),
append(Sub1, Seen, Seen1),
remove(Subs, Result, Seen1).
remove([], [], _).
So basically now I'm keeping a "seen" list. Right before the recursive call, I stitch together the stuff I've seen so far and the elements of this list. This is not particularly efficient, but it seems to get the job done:
?- remove([[a,m,t,a],[k,a,w],[i,k,b,b],[z,m,m,c]], R).
R = [[t], [w], [i, b, b], [z, c]].
This strikes me as a pretty nasty problem. I'm surprised how nasty it is, honestly. I'm hoping someone else can come along and find a better solution that reads better.
Another thing to investigate would be DCGs, which can be helpful for doing these kinds of list processing tasks.
What does it mean to put the cut (!) at the very beginning of a clause?
p(X,Y) :- !, q(X), r(X,Y).
What is the difference between ! and fail and how are they related?
thanks.
I'm thinking that for fail, the predicate will just "fail" lol which is different from not backtracking? just want to be sure :)
Usually, you use this when you want to make sure that there is no backtracking on a certain combination of variable instantiations. To show some code (borrowed a bit from the SWI-Prolog implementation:
read_lines(In, Ls) :-
read_line_to_codes(In, Codes),
read_lines_rest(Codes, In, Ls).
read_lines_rest(end_of_file, _, []) :- !.
read_lines_rest(Codes, In, [Codes|Rest]) :-
read_line_to_codes(In, New_codes),
read_lines_rest(New_codes, In, Rest).
Now, with these predicates defined, you can read an input stream (a file, for example) to a list of lines. We are using read_line_to_codes/2 from library(readutil). It will unify its second argument with a list of codes representing a line, or the atom end_of_file at the end of input.
In the first clause of read_lines_read/3, we use unification in the head of the predicate definition. We "demand" that the first argument must be the atom end_of_file if we want the predicate to be even considered. When (at the end of input) this clause succeeds, the other possible solution in the second clause of the definition is not taken in consideration, and the predicate succeeds, closing up the list in the third argument.
Here it is used:
?- open('shortcut.pl', read, In), read_lines(In, Ls), forall(member(L,Ls), format("~s~n", [L])).
read_lines(In, Ls) :-
read_line_to_codes(In, Codes),
read_lines_rest(Codes, In, Ls).
read_lines_rest(end_of_file, _, []) :- !.
read_lines_rest(Codes, In, [Codes|Rest]) :-
read_line_to_codes(In, New_codes),
read_lines_rest(New_codes, In, Rest).
% variable instantiations
You should notice that the predicate succeeds exactly once. Try removing the cut in the first clause to see what happens.
As for the fail, yes, it makes the predicate fail (not succeed). At this point, if there are any choice points left, Prolog will backtrack to the most recent one.
I'm trying to further my understanding of Prolog, and how it handles unification. In this case, how it handles unification with lists.
This is my knowledgebase;
member(X, [X|_]).
member(X, [_|T]):- member(X, T).
If I'm understanding the process correctly. If member(X, [X|_]) is not true, then it moves into the recursive rule, and if X is in list T, then [_|T] is unified with T.
So what happens to the anonymous variable in my recursive predicate? Does it get discarded? I'm having difficulty understanding the exact unification process with lists, as [_|T] is two variables, rather than one. I'm just trying to figure out how the unification process works precisely with lists.
Assume that _ is Y
member(X, [Y|T]):- member(X, T).
Then this is True regardless Y. Now you are "returning" member(X, T). In other words, you are discarding Y and "returning" member(X, T).
_ means, whatever it is, ignore that variable.
The _ is just like any other variable, except that each one you see is
treated as a different variable and Prolog won't show you what it
unifies with. There's no special behavior there; if it confuses you
about the behavior, just invent a completely new variable and put it
in there to see what it does.
In your case, your function check if a given element exists on a list, so, you take first element of the list, check if is equal, if not, you discard that element and moves on.
I think your primary question of how lists are represented as variables has been adequately answered, but I sense there are some other aspects to Prolog that need clarification.
To understand Prolog predicates and clauses, it's a good idea not to think of them as "functions" that "return" things, even metaphorically. It can lead you down the dark path of imperative thinking in Prolog. :)
In considering the predicate:
(1) member(X, [X|_]).
(2) member(X, [_|T]) :- member(X, T).
Think of member/2 as a relation which describes when element X is a member of the list L, and the clauses are the rules for determining when it is true.
I'll assume that you already know about how lists are represented in Prolog based upon other answers (e.g., Will Ness' detailed answer).
The first clause says:
(1) X is a member of [X|_] regardless of what the tail of the list [X|_] is
In that notation, the variable _ represents the tail of list [X|_] and X represents the first element of that list. It's trivially true that X is a member of this list, so member(X, [X|_]). is a fact. It's true regardless of what the tail of the list is, so we just use _ (an anonymous variable) since this rule doesn't need the information. Prolog doesn't technically "throw the value away" but the programmer throws it away because the programmer isn't using it. If we had, instead, said, member(X, [X|T]). that would work fine, but we're not using T. Prolog might instantiate it, but it wouldn't be used. It's like assigning x = 3 in C but not using it's value. In this case, Prolog will indicate a warning about a "singleton" variable. Watch for those, because it often means you misspelled something or forgot something. :)
The next rule is recursive. It says:
(2) X is a member of list [_|T] if X is a member of the tail (T) of that list, regardless of what the first element of the list is
Here we're considering the less trivial case where the first element in the list may not be a match to X, so the truth value of member(X, L) depends, in this rule, upon the truth value of member(X, T) where T is the tail (everything but the first element) of L. The rule does not unify member(X, [_|T]) with member(X, T), so it does not unify T with [_|T] as you might suppose. The :- operator defines a rule or implication (note the if in the rule description). [N.B., If you were to unify these terms, it would be done with with the unification operator, =/2: member(X, [_|T]) = member(X, T)].
On the recursive query member(X, T), Prolog goes back to the top, the first rule, and attempts to unify the first argument X with the head of the second argument (which is the original list minus its first element, or head) and, if it doesn't match, goes to rule #2 again, continually checking the tail as well, until it can unify. If it gets to the point where the tail is empty ([]) and hasn't been able to unify X with any elements, the predicate fails because there are no facts or rules that match member(X, []). However, if it does unify X with an element, it succeeds (it does not "return a value* in the sense that a function would in other languages) and reveals the values of any variables it instantiated in the arguments in the process, or simply will succeed if all the arguments passed are already instantiated. If there are more rules to check after succeeding (there was what's called a choice point), it will (if you tell it to) go back and check for more solutions and, if it finds them, display them as well. Or display no or false if there are no more.
Looking at an example query, is b a member of [a,b,c]?
member(b, [a,b,c]).
Prolog will first try to unify the query with a fact or the head of a predicate. The first one it finds is:
member(X, [X|_]).
In attempting to unify, X = b, but [a,b,c] (or, [a|[b,c]] in the head-tail notation) doesn't unify with [b|_](note the head elementsaandb` mismatch). Prolog then moves on to the next clause:
member(X, [_|T]) :- member(X, T).
In unifying member(b, [a,b,c]) with the head, it comes up with:
member(b, [_|[b,c]]) :- member(b, [b,c]).
It now has the recursive query to chase down: member(b, [b,c]). Since it's a new query, it starts at the top again and attempts to unify this with member(X, [X|_]). Now, it's successful, because member(b, [b,c]) (or, member(b, [b|[c]])) matches this pattern: member(b, [b|_]).
Therefore, the member(b, [a,b,c]). succeeds and Prolog will return "true". However, it's not done yet because it left what's called a choice point. Even though it matched member(b, [b,c]) with the first clause, it will still want to go back and find more cases that make it succeed, and there's still another clause to pursue. So, Prolog will go back and try member(b, [b,c]) against the second clause, matching member(b, [b|[c]]) to member(b, [_|[c]]) and doing another recursive query, member(b, [c]) and so on until it ultimately fails to find another solution. This is why the query looks something like this:
| ?- member(b, [a,b,c]).
true ? ;
no
| ?-
It first succeeds, but then we ask for more (with ;) and it then fails (no). This confuses some Prolog beginners, but it's because we've asked Prolog to get another solution, and it said there are none.
Because Prolog continues to try to find solutions (upon request), you can also use a variable in the query:
member(E, [a,b,c]).
This query runs the same way as the prior example, but now I have a variable as the first argument. Prolog will successfully match this to the first clause: member(E, [a,b,c]) unifies with member(X, [X|_]) via E = a. So you'll see something like:
| ?- member(E, [a,b,c]).
E = a ?
If we now ask for more solutions with ;, Prolog goes back and attempts the second clause, unifying member(E, [a|[b,c]]) with member(X, [_|T]) yielding _ = a (which is ignored in the predicate) and T = [b,c]. It then recursively queries, member(E, [b,c]) and, since it's a new query, goes back to the top and matches member(X, [X|_]) again, this time with E = b. So we see:
| ?- member(E, [a,b,c]).
E = a ? ;
E = b ?
And so on. member(E, [a,b,c]) will find all the values of E which make member(E, [a,b,c]) true and then finally fail after exhausting all the elements of [a,b,c]).
[A|B] represents a list where A is the Head element and B is the whole rest list.
So to explain you the algorithm shortly:
Clause: If X is the first element of the list the predicate succeeds.
Clause: If that's not the case, we try to find X in the tail of the list. Therefore, we call member recursively but instead of passing the whole list we now pass the list EXCEPT the head element. In other words, we walk through the list step by step always looking at the head element first. If that is not our element, we dig further.
Think of the anonymous variable _ just as a variable you do not need later. The algorithm would also work, if you replaced _ by a capital letter, however it would give you a warning that you named a variable that you never use.
A list is just a compound term with the '.' functor:
1 ?- [_|T] = .(_,T).
true.
2 ?- [_|T] =.. X.
X = ['.', _G2393, T].
The usual process of structural unification of compound terms apply:
3 ?- [A|T] = .(B,R).
A = B,
T = R.
[A|T] is really .(A,T) so the functors (.) and the arities (both terms are binary, of arity 2) match, so the respective constituents are matched as well.
Yes, the anonymous variable _ is ignored for the purposes of reporting the unification results. Otherwise it is just a fresh uniquely named variable.
it moves into the recursive rule, and if X is in list T, then [_|T] is unified with T.
Not quite. The unification happens before the "moving on", as part of the clause selection. To unify a list L with [_|T] is to select its "tail" and have T referring to it. E.g.
4 ?- L = [1,2,3], L = [_|T].
L = [1, 2, 3],
T = [2, 3].
(_ is 1 but is not reported).
When you call member(Item, List) with an uninstanciated list, Prolog unifies and returns a list containing item. I want a rule that returns true/false and does not try to unify. Is there such a rule?
Quick answer: Use \+ \+ member(Item, List).
Please note that such tests often do not make a lot of sense when your programs represent logical relations.
You stated that member(Item, List) "returns a list". Well, that is not entirely true. List is unified with partial lists, that is List = [Item|_Rest] ; List = [_,Item|_Rest] ; ... with _Rest being an uninstantiated variable. That is, the goal member(Item, List) does not guarantee that (upon success) List is a list. Here is a counterexample: member(Item, List), List = [_|nonlist]
I would use a guard, like
is_member(E, L) :- nonvar(L), memberchk(E, L).
memberchk/2 it's a deterministic version of member/2, to be used to find if the list contains at least 1 occurrence of element. Cannot act as a generator, but it's more efficient. The guard is required anyway.
The builtin predicate setof/3 can be used to create an ordered list without duplicates.
Can I also use it to test whether a list represents a set with no duplicates? Like this?
no_duplicates(L) :- setof(_,_,L).
You cannot use it in exactly the way you describe. BUT, You can use setof to determine if a list is a set if you ask it to iterate through your list for members, then check the set against the original. If they have the same length, then all elements were unique.
no_duplicates(L) :-
setof(X, member(X, L), Set),
length(Set, Len),
length(L, Len).
You can't. Your arguments are not sufficiently instantiated.
If you are using SWI-Prolog you can use the predicate
is_set/1 in the lists module.