I'm attempting to make a predicate that takes a list of pairs and, if it finds the key in the list it will remove that item from the list and return the rest. However, it also needs to return the full list if the key given does not exist.
unmap(K, M1, M2):-
select(E, M1, MM1),
select(E, [(K, _)], K1),
unmap(MM1, K1, M2).
unmap(X, _, X).
Called with:
unmap(key1, [(key1, value1),(key2, value2),(key3, value3)], R).
Results in:
R = [(key2, value2), (key3, value3)]
Works, but theres a problem. I'm trying to make it return the identical list thats given if the key1 does not exist. Here's what it returns:
Calling:
unmap(key4, [(key1, value1),(key2, value2),(key3, value3)], R).
Returns:
R = key4
I think it's something to do with my terminating rule, but I'm not sure how to go about fixing it. Thanks very much in advance for all that can help.
Of course, you can do it with logical-purity! Here's how...
Let's call the actual relation pairs_key_unmapped/3. That's a somewhat more descriptive name. unmap/3 is just a wrapper for pairs_key_unmapped/3:
unmap(Key,Ps0,Ps) :-
pairs_key_unmapped(Ps0,Key,Ps).
The implementation of pairs_key_unmapped/3 is built on the predicates if_/3 and =/3 (a.k.a. equal_truth/3), as defined by #false in an answer to "Prolog union for A U B U C":
pairs_key_unmapped([],_,[]).
pairs_key_unmapped([P|Ps],K,Us) :-
P = (K0,_),
if_(K0=K, Ps=Us, (Us=[P|Us0],pairs_key_unmapped(Ps,K,Us0))).
Let's run some queries!
?- unmap(key1,[(key1,value1),(key2,value2),(key3,value3)],Ps).
Ps = [(key2,value2),(key3,value3)]. % succeeds deterministically
?- unmap(key4,[(key1,value1),(key2,value2),(key3,value3)],Ps).
Ps = [(key1,value1),(key2,value2),(key3,value3)]. % succeeds deterministically
Let's try something different... What if Key occurs twice in Ps0?
?- unmap(key1,[(key1,x),(key1,y)],Ps). % only the 1st occurrence is removed
Ps = [(key1,y)]. % succeeds deterministically
What if Ps0 is unknown, but Ps is known?
?- unmap(key4,Ps0,[(key1,value1),(key2,value2),(key3,value3)]).
Ps0 = [(key4,_A), (key1,value1),(key2,value2),(key3,value3)] ;
Ps0 = [(key1,value1),(key4,_A), (key2,value2),(key3,value3)] ;
Ps0 = [(key1,value1),(key2,value2),(key4,_A), (key3,value3)] ;
Ps0 = [(key1,value1),(key2,value2),(key3,value3) ] ;
Ps0 = [(key1,value1),(key2,value2),(key3,value3),(key4,_A) ] ;
false.
How about something a little more general?
?- unmap(Key,Ps0,[_,_]).
Ps0 = [(Key,_A),_B, _C ] ;
Ps0 = [(_A,_B), (Key,_C), _D ], dif(_A,Key) ;
Ps0 = [(_A,_B), (_C,_D) ], dif(_A,Key), dif(_C,Key) ;
Ps0 = [(_A,_B), (_C,_D), (Key,_E)], dif(_A,Key), dif(_C,Key) ;
false.
And what answers does the most general query give us?
?- unmap(Key,Ps0,Ps).
Ps0 = [], Ps = [] ;
Ps0 = [(Key,_A)|Ps] ;
Ps0 = [(_A,_B)], Ps = [(_A,_B)], dif(_A,Key) ;
Ps0 = [(_A,_B),(Key,_C)|_Z], Ps = [(_A,_B)|_Z], dif(_A,Key) ;
Ps0 = [(_A,_B),(_C,_D)], Ps = [(_A,_B),(_C,_D)], dif(_A,Key), dif(_C,Key) ...
The issue is with your base case:
unmap(X, _, X).
If your main predicate clause fails (the key isn't found), it reverts to the base case, which will instantiate your result (third argument) with only the key (first argument). Your base case should be:
unmap(_, X, X).
Which will instantiate the result (third argument) with the original list (second argument).
Note that the main clause could be simpler (this will work in GNU or SWI prolog):
unmap(K, M, R):-
select((K, _), M, M1),
unmap(K, M1, R), !.
The cut prevents backtracking to the base case if the first clause succeeds.
In SWI Prolog, the delete/3 predicate will work in your favor:
unmap(K, M, R) :-
delete(M, (K,_), R), !.
delete/3 is more strict in GNU Prolog and will not work in this case.
This isn't so much an answer to the question, but a simpler way of attacking it, without using the 'select' (or any other built-in predicates), and only using recursion.
Considering that the output list is just a list of items that didn't match the key, you need 2 main clauses, and iterate around the list. One where the key matches the head of the list, and one that doesn't.
unmap(_, [], []).
% head of the list matches key, do not add K/H to unmatched list (ie remove it)
unmap(K, [(H, _)|Tail], Unmatched) :-
H == K,
unmap(K, Tail, Unmatched).
% above rule fails, add H to unmatched list
unmap(K, [H|Tail], [H|Unmatched]) :-
unmap(K, Tail, Unmatched).
?- unmap(key1, [(key1, value1),(key2, value2),(key3, value3)], R).
R = [ (key2, value2), (key3, value3)] .
?- unmap(key4, [(key1, value1),(key2, value2),(key3, value3)], R).
R = [ (key1, value1), (key2, value2), (key3, value3)] .
So if the key doesn't exist, it just iterates around adding all list items, and so the input and output lists are identical.
Related
I need to convert a list of elements into a list of lists.
For example, if i have the list [1,2,3,4] the output must be [[1],[2],[3],[4]], one element per list.
create([],_, _, _).
create([H|T], Aux, X, Result) :-
append([H], Aux, X),
Result = [X],
create(T, X, _, Result).
I always get false... is this even possible to do?
Another possibility to define this relation is by using DCGs. They yield easily readable code when describing lists. Let's stick with the name singletons as suggested by #false in the comments:
singletons([]) --> % the empty list
[]. % is empty
singletons([H|T]) --> % the head of a nonempty list
[[H]], % is a list on its own
singletons(T). % and so is the tail
You can query this directly with phrase/2:
?- phrase(singletons([1,2,3,4]),X).
X = [[1],[2],[3],[4]]
Or write a wrapper-predicate with phrase/2 as the single goal:
singletons(L,Ls) :-
phrase(singletons(L),Ls).
And query that:
?- singletons([1,2,3,4],Ls).
Ls = [[1],[2],[3],[4]]
The predicate also works the other way around:
?- singletons(L,[[1],[2],[3],[4]]).
L = [1,2,3,4] ? ;
no
As well as the most general query:
?- singletons(L,Ls).
L = Ls = [] ? ;
L = [_A],
Ls = [[_A]] ? ;
L = [_A,_B],
Ls = [[_A],[_B]] ?
...
Alternatively you can also define a simple predicate that describes a relation between an arbitrary element and itself in brackets and then use maplist/3 from library(apply) to apply it on every element of a list:
:- use_module(library(apply)).
embraced(X,[X]).
singletons(L,Ls) :-
maplist(embraced,L,Ls).
This version yields the same results for the above queries. However, it is more efficient. To see that consider the following query from above:
?- singletons(L,[[1],[2],[3],[4]]).
L = [1,2,3,4]
Above you had to enter ; to make Prolog search for further solutions and subsequently fail (indicated by no). With this version there are no unnecessary choice points left and Prolog is succeeding deterministically for the query.
Try this
create([],[]).
create([H|T],[[H]|T2]):- create(T,T2).
I tried
?- create([1,2,3,4],X).
and the result was
X = [[1], [2], [3], [4]].
I want to do some if | else stuff in prolog. Below is my code, Prolog will return 'R = false' if my input list is not empty, it will return 'false' if my list is empty. What do I miss?
Code:
isEmpty([H|T],R) :-
length([H|T],L),
( L > 0 -> R = 'false'
;
L =:= 0 -> R = 'true'
).
Prolog Output:
1 ?- isEmpty([],R).
false.
2 ?- isEmpty([1],R).
R = false.
3 ?- isEmpty([1,2,3],R).
R = false.
One way to define this would be to use unification ("pattern matching"):
list_empty([], true).
list_empty([_|_], false).
If you insist on using an if-then-else, you need to pass the list without trying to match it in any way:
list_zerolength(List, Empty) :-
length(List, Len),
( Len == 0
-> Empty = true
; Empty = false
).
... but this is not optimal. The two predicates behave identically if the first argument is indeed a list:
?- list_empty([], R).
R = true.
?- list_empty([_], R).
R = false.
?- list_zerolength([], R).
R = true.
?- list_zerolength([_], R).
R = false.
However, something annoying happens if the first argument is not ground (that is, is not fully instantiated):
?- list_zerolength(L, true).
L = [] ;
ERROR: Out of global stack
So, we try to ask for an empty list, and we get it; however, Prolog insists there might be another answer. When we try to get it, we get an error.
(Extra credit: figure out what happens!)
The predicate list_empty/2 is not perfect, either. Consider:
?- list_empty([_|a], R).
R = false.
This succeeds, and we could interpret the answer as: "The list [_|a] is not empty". However, this is not ever a proper list!
?- is_list([_|a]).
false.
Using length/2 is not at all a bad idea. We can use it to write a predicate that is arguably a bit more useful than list_empty/2. I call it list_nonempty/2 to confuse the situation:
list_nonempty([], false).
list_nonempty([_|T], true) :-
length(T, _).
length/2 does a lot more than just finding the length of a list. It can be used to generate lists of increasing length, or check whether its first argument is a proper list:
?- list_nonempty(L, NE).
L = [],
NE = false ;
L = [_G904],
NE = true ;
L = [_G904, _G907],
NE = true . % and so on
?- list_nonempty(L, false).
L = [].
?- list_nonempty([], true).
false.
?- list_nonempty([_|a], true).
ERROR: length/2: Type error: `list' expected, found `a' (an atom)
SWI-Prolog throws an error when length/2 is not given a list. Implementations that are more committed to ISO-compliance should fail instead. With GNU Prolog:
?- list_nonempty([_|a], true).
no
I know it's old thread but still this might be useful for those using SWI-Prolog. Instead of defining their own rules, you can try:
nth0(0, List, _).
It is used to return the first element on the list, which in case of empty list simply fails.
Since you are only dealing with lists of the form [H|T] your clauses will only match for lists that have at least one list element. In other words, you get the answer false for the empty list because there is not a matching clause - not because the length is 0.
How can I search a list in Prolog for a specific element that appears more than once?
For example, if we are searching the list [1,2,3,4,1] for the element 1, Prolog should return true, but otherwise false for all other numbers.
This is what I have so far:
duplicate([], _) :-
false,
!.
duplicate([X|_], X) :-
true,
!.
duplicate([H|T], X) :-
T = [_|T1],
duplicate(T, X),
duplicate(T1, X).
My basic idea is to search the list until I find the element I am looking for, then search the tail of the list for the item again. I do not want to use the member() function provided by Prolog.
Prolog should also return the elements that appear more than once if asked by the query: duplicate([1,2,3,4,1], X), should print X = 1.
And here the obvious version using grammars. In a sense, we are describing the structure of a list containing a duplicate. That structure is as follows:
First, there is anything (...),
then there is the element ([V]),
again anything (...)
and again the element ([V])
followed by anything.
duplicate(L, V) :-
phrase(( ..., [V], ..., [V], ... ), L).
... --> [] | [_], ... .
As a downside, this version will produce redundant answers for a query like
?- duplicate([a,a,a],a).
This can be overcome by using dif/2:
duplicate(L, V) :-
phrase(( all(dif(V)), [V], all(dif(V)), [V], ... ), L).
The definition for non-terminal all//1.
What I was saying in my comment was : I want two items from the list L wich are not in the same place so
duplicate(L, V) :-
% nth0 gives the index (from 0) of an element in a list
% element V is at the place Id1 in L
nth0(Id1, L, V),
% element V is at the place Id2 in L
nth0(Id2, L, V),
% Id1 is different from Id2
% It is more usefull to say that Id1 < Id2
% Thanks **false** for the improvement
Id1 < Id2.
Another way to do this is to say : I remove the element of the list (this is done in SWI-Prolog by select/3) and I check if it's in the rest of the list :
duplicate(L, V) :-
select(V, L, L1),
member(V, L1).
Pure and simple! Use meta-predicate tcount/3 with reified term equality (=)/3 like so:
?- tcount(=(X), [1,2,3,4,1], 2).
X = 1 ; % succeeds, but leaves choicepoint
false.
?- tcount(=(1), [1,2,3,4,1], 2).
true. % succeeds deterministically
?- tcount(=(X), [b,c,d,a,b,a,c], 2).
X = b ;
X = c ;
X = a ;
false.
?- tcount(=(a), [b,c,d,a,b,a,c], 2).
true. % succeeds deterministically
Last, let's run the following quite general query:
?- tcount(=(a), Ls, 2).
Ls = [a,a] ;
Ls = [a,a,_X], dif(_X,a) ;
Ls = [a,a,_X,_Y], dif(_X,a), dif(_Y,a) ;
Ls = [a,a,_X,_Y,_Z], dif(_X,a), dif(_Y,a), dif(_Z,a) ...
The solution by #false is as clean as it will get. Here is a more verbose solution that states the problem in simpler terms. One thing to remember is that a "duplicated" element might mean that an element occurs exactly twice -- this is how this predicate interprets it -- or it might mean that an element occurs more than once -- this is what you probably mean (so the name duplicate is in fact misleading)
%% duplicate(List, Element) is true for every matching pair of _Element_ in _List_
duplicate([First|Rest], Element) :-
duplicate_1(Rest, First, Element).
% First occurrence
duplicate_1([This|Rest], X, X) :- % first occurrence
duplicate_2(Rest, This, X).
duplicate_1([This|Rest], _, X) :- % look further for first occurrence
duplicate_1(Rest, This, X).
% Second occurrence
duplicate_2(_, X, X). % second occurrence
duplicate_2([This|Rest], _, X) :- % look further for second occurrence
duplicate_2(Rest, This, X).
This can now be used in all directions:
?- duplicate([b,c,d,a,b,a,c], X).
X = b ;
X = c ;
X = a ;
false.
?- duplicate([b,c,d,a,b,a,c], a).
true ;
false.
?- duplicate(L, a).
L = [a, a|_G274] ;
L = [a, _G273, a|_G277] ;
L = [a, _G273, _G276, a|_G280] .
You will have to use cuts, or dif/2, or once/1 to get rid of the multiple answers, if they are a problem. How exactly depends on how you want to use the predicate.
for the first part of your problem I have found a simple solution:
duplicated([H|T], Item) :- H == Item, second_stage(T, Item). %first occurence found
duplicated([H|T], Item) :- duplicated(T, Item).
second_stage([H|T], Item) :- H == Item. %second occurence found -> match!
second_stage([H|T], Item) :- second_stage(T, Item).
This will give true f.e. with duplicated([1,2,3,1,5], 1).
For the second part (query with Variable) I will try to find a way...but I dont
know if this is possible in Prolog.
:)
Again a Prolog beginner :-}
I build up a list element by element using
(1)
member(NewElement,ListToBeFilled).
in a repeating call,
(2)
ListToBeFilled = [NewElement|TmpListToBeFilled].
in a recursive call like
something(...,TmpListToBeFilled).
A concrete example of (2)
catch_all_nth1(List, AllNth, Counter, Result) :-
[H|T] = List,
NewCounter is Counter + 1,
(
0 is Counter mod AllNth
->
Result = [H|Result1]
;
Result = Result1
),
catch_all_nth1(T,AllNth,NewCounter,Result1),
!.
catch_all_nth1([], _, _, _).
As result I get a list which looks like
[E1, E2, E3, ..., Elast | _G12321].
Of course, the Tail is a Variable. [btw: are there better method to fill up the
list, directly avoiding the "unassigned tail"?]
I was now looking for a simple method to eliminate the "unassigned tail".
I found:
Delete an unassigned member in list
there it is proposed to use:
exclude(var, ListWithVar, ListWithoutVar),!,
[Found this too, but did not help as I do not want a dummy element at the end
Prolog list has uninstantiated tail, need to get rid of it ]
What I noticed is that using length\2 eliminate the "unassigned tail", too, and in addtion
the same List remains.
My Question is: How does it work? I would like to use the mechanism to eliminate the unassigned tail without using a new variable... [in SWI Prolog 'till now I did not get the debugger
entering length() ?!]
The example:
Z=['a','b','c' | Y],
X = Z,
write(' X '),write(X),nl,
length(X,Tmp),
write(' X '),write(X),nl.
13 ?- test(X).
X [a,b,c|_G3453]
X [a,b,c]
X = [a, b, c] .
I thought X, once initialized can not be changed anymore and you need
a new variable like in exclude(var, ListWithVar, ListWithoutVar).
Would be happy if someone explain the trick to me...
Thanks :-)
You're right about the strange behaviour: it's due to the ability of length/2 when called with unbound arguments
The predicate is non-deterministic, producing lists of increasing length if List is a partial list and Int is unbound.
example:
?- length([a,b,c|X],N).
X = [],
N = 3 ;
X = [_G16],
N = 4 ;
X = [_G16, _G19],
N = 5 ;
...
For your 'applicative' code, this tiny correction should be sufficient. Change the base recursion clause to
catch_all_nth1([], _, _, []).
here are the results before
4 ?- catch_all_nth1([a,b,c,d],2,1,R).
R = [b, d|_G75].
and after the correction:
5 ?- catch_all_nth1([a,b,c,d],2,1,R).
R = [b, d].
But I would suggest instead to use some of better know methods that Prolog provide us: like findall/3:
?- findall(E, (nth1(I,[a,b,c,d],E), I mod 2 =:= 0), L).
L = [b, d].
I think this should do it:
% case 1: end of list reached, replace final var with empty list
close_open_list(Uninstantiated_Var) :-
var(Uninstantiated_Var), !,
Uninstantiated_Var = '[]'.
% case 2: not the end, recurse
close_open_list([_|Tail]) :-
close_open_list(Tail).
?- X=[1,2,3|_], close_open_list(X).
X = [1, 2, 3].
Note that only variable X is used.. it simply recurses through the list until it hits the var at the end, replaces it with an empty list, which closes it. X is then available as a regular 'closed' list.
Edit: once a list element has been assigned to something specific, it cannot be changed. But the list itself can be appended to, when constructed as an open list ie. with |_ at the end. Open lists are a great way to build up list elements without needing new variables. eg.
X=[1,2,3|_], memberchk(4, X), memberchk(5,X).
X = [1, 2, 3, 4, 5|_G378304]
In the example above, memberchk tries tries to make '4', then '5' members of the list, which it succeeds in doing by inserting them into the free variable at the end in each case.
Then when you're done, just close it.
Hi i was wondering if you could help me out with this
From programming in Prolog: write Prolog script for replacement any given element in lists by an another given element. For example:
replace( 3, a,[1,2,3,4,3,5], [1,2,a,4,a,5])=true
Many Thanks in advance
In Prolog, most list processing is done by processing the head and then recursively processing the rest of the list. Of course, you can't forget about the base case, which is an empty list.
Replacing anything with anything in an empty list results again in an empty list. If the head of the list is the same as the element to replace, replace it, otherwise, keep it as it is. In both cases, process recursively the rest of the list. Translated from English into Prolog:
replace(_, _, [], []).
replace(O, R, [O|T], [R|T2]) :- replace(O, R, T, T2).
replace(O, R, [H|T], [H|T2]) :- H \= O, replace(O, R, T, T2).
All implementations presented so far in other answers are logically unsound when being used with non-ground terms. Consider the original query and a slight variant:
?- replace(3,three,[1,2,3],Xs).
Xs = [1,2,three] ; % OK: correct
false
?- A=3, replace(A,B,[1,2,3],Xs). % OK: correct
Xs = [1,2,B], A = 3 ;
false
It works! Let's ask some very similar queries:
?- replace(A,B,[1,2,3],Xs). % FAIL: should succeed more than once...
Xs = [B,2,3], A = 1 ; % ... but the other solutions are missing
false
?- replace(A,B,[1,2,3],Xs), A=3. % FAIL: this query _should_ succeed ...
false % ... it does not!
What's going on? Put the blame on meta-logical builtins (!)/0 and (\=)/2, which are very hard to use right and often make code brittle, impure, and logically unsound.
To preserve logical soundness, stick to logical purity and abstain from meta-logical "features" whenever possible! Luckily, most Prolog implementations support dif/2 as a logical alternative to (\=)/2. Let's use it:
% code by #svick, modified to use dif/2 instead of (\=)/2
replaceP(_, _, [], []).
replaceP(O, R, [O|T], [R|T2]) :- replaceP(O, R, T, T2).
replaceP(O, R, [H|T], [H|T2]) :- dif(H,O), replaceP(O, R, T, T2).
Let's run above queries again, this time with the improved replaceP/4:
?- replaceP(3,three,[1,2,3],Xs).
Xs = [1,2,three] ; % OK: correct, like before
false
?- replaceP(A,B,[1,2,3],Xs). % OK: four solutions, not just one
Xs = [B,2,3], A = 1 ;
Xs = [1,B,3], A = 2 ;
Xs = [1,2,B], A = 3 ;
Xs = [1,2,3], dif(A,1),dif(A,2),dif(A,3) ;
false
?- replaceP(A,B,[1,2,3],Xs), A=3. % OK (succeeds now)
Xs = [1,2,B], A = 3 ;
false
?- A=3, replaceP(A,B,[1,2,3],Xs). % OK (same as before)
Xs = [1,2,B], A = 3 ;
false
replace(_, _ , [], []).
replace(X, Y, [ X | Z ], [ Y | ZZ]):- ! , replace( X, Y, Z, ZZ).
replace(X, Y, [ W | Z], [ W | ZZ] :- replace(X, Y, Z, ZZ).
Though, one would usually arrange the 3. arg to be the first one. And strictly speaking above does not replace anything in the list, it just anwsers if 4th arg is like the one in the 3rd but with Y' instead of X'.
replace(E,S,[],[]).
replace(E,S,[E|T1],[S|T2]):-replace(E,S,T1,T2).
replace(E,S,[H|T1],[H|T2]):-E\=H, replace(E,S,T1,T2).
the idea is simple, if the elements match, change it, if not, go forward until empty.
domains
I=integer*
K=integer*
Z=integer
A=integer
predicates
nondeterm rep(I,Z,A,K)
clauses
rep([],_,_,[]).
rep([Z|T1],Z,A,[A|T2]):- rep(T1,Z,A,T2).
rep([H|T1],Z,A,[H|T2]) :- rep(T1,Z,A,T2).
goal
rep([1,2,3],2,4,X).