I have a list, for example [(1,2), (3,4), (5,2), (4,2), (8,0)], and I want to remove, for example, all elements that are not (_,2). So in this case, I'd end up with a list like this: [(1,2), (5,2), (4,2)].
I was trying:
conta_pos(NL, _, NL):-
Idk what to do here, !.
conta_pos([(L,C)|T], C, _):-
conta_pos_aux([()], C, _).
conta_pos([(_,C)|T], _, _):-
conta_pos(T, _, _).
The first argument represents the initial list, the second is the element I want the list to keep, and the third would be my new list.
Keep in mind that I'm very new to Prolog, please.
(The actual thing I want to do is to count the number of elements in the initial that are, in this example (_, 2), so that would 3. I was thinking of then using length\2 to count them, but if you have a better suggestion, I'm all open to it! And if you want to know what the whole thing I have to do is, feel free to ask)
You're describing lists, so you could use DCGs for the task, since they usually yield easily readable code. Furthermore, you could use an additional argument to count the elements in the list as it's being traversed. Consider the following code:
list_filtered_length(L,F,Len) :- % the filtered list F is described
phrase(filtered_len(L,Len,0),F). % by the DCG filtered_len//3
filtered_len([],N,N) --> % if the list is empty, the counter is the length
[]. % and the filtered list is empty
filtered_len([(A,2)|Ps],N,C0) --> % if the head of the list is (A,2)
{C1 is C0+1}, % the counter is increased
[(A,2)], % (A,2) is in the filtered list
filtered_len(Ps,N,C1). % the same for the tail
filtered_len([(_,B)|Ps],N,C) --> % if the head of the list is (_,B)
{dif(B,2)}, % with B not being 2, it's not in the list
filtered_len(Ps,N,C). % the same for the tail
Querying this predicate with your example yields the desired result:
?- list_filtered_length([(1,2),(3,4),(5,2),(4,2),(8,0)],F,Len).
F = [ (1, 2), (5, 2), (4, 2)],
Len = 3 ;
false.
Obviously, if you want to apply a different filter, you have to rewrite the two recursive DCG rules. It would be nicer to have the filter defined as a separate predicate and to pass it as an argument, therefore making the predicate more versatile. It would also be nice to have the predicate succeed deterministically if there's only a single solution. This can be realized with if_/3 and (=)/3. In order to be used as the first argument of if_/3, the filter predicate needs to reify its truth value as an additional argument:
filter_t((_,X),T) :-
if_(X=2,T=true,T=false).
As you can see, the last argument is true if the filter condition holds and false otherwise:
?- filter_t((1,1),T).
T = false.
?- filter_t((1,2),T).
T = true.
Now the predicate can be redefined with an additional argument for the filter like so:
list_filtered_by_length(L,LF,F_2,Len) :- % F_2 is the filter argument
phrase(filtered_by_len(L,F_2,Len,0),LF).
filtered_by_len([],_F_2,N,N) -->
[].
filtered_by_len([P|Ps],F_2,N,C0) -->
{if_(call(F_2,P),(X=[P], C1 is C0+1),
(X=[], C1 = C0))},
X, % X is in the filtered list
filtered_by_len(Ps,F_2,N,C1).
If the head of the list meets the filter condition (call(F_2,P)), it is in the filtered list (X=[P]) and the counter is increased (C1 is C0+1), otherwise it is not in the list (X=[]) and the counter is not increased (C1 = C0).
Now the example query succeeds deterministically:
?- list_filtered_by_length([(1,2),(3,4),(5,2),(4,2),(8,0)],F,filter_t,Len).
F = [ (1, 2), (5, 2), (4, 2)],
Len = 3.
If you want to filter for something else, just define a different filter predicate. For example, if you want to filter all pairs of equal elements from a list of pairs, you can define...
filter2_t(X-Y,T) :-
if_(X=Y,T=true,T=false).
... and then query:
?- list_filtered_by_length([a-a,b-c,d-d,e-f],F,filter2_t,Len).
F = [a-a, d-d],
Len = 2.
EDIT
Alternatively, you can express this relation quite compactly by using tfilter/3, as suggested by #false in the comments. Just as with the DCG version you pass a reifying filter predicate as third argument that is then used as the first argument of tfilter/3. Subsequently the length of the filtered list is described by the built-in length/2.
list_filtered_by_length(L,FL,F_2,Len) :-
tfilter(F_2,L,FL),
length(FL,Len).
The above queries yield the same answers as with the DCG version.
In general, suppose that you have a predicate some_condition(...other_args..., X) that succeeds if you want to keep X and fails otherwise. A simple recursion to do the filter would be:
filter([], _, []).
filter([X|Xs], Condition, Ys) :-
( call(Condition, X)
-> Ys = [X|Zs]
; Ys = Zs
),
filter(Xs, Condition, Zs).
You can then call this as:
filter(RawList, some_condition(...other args...), FilteredList).
In this specific case, the condition you want to check is whether the argument matches (_,2). The simplistic condition would be:
second_arg_2((_,2)). % Succeeds if second argument is a 2
You can make the condition as sophisticated as you wish to handle more cases.
Then you can call:
| ?- filter([(1,2), (3,4), (5,2), (4,2), (8,0)], second_arg_2, R).
R = [(1,2),(5,2),(4,2)]
yes
You can then, of course, count the results if you want using length/2.
For the count of (_,2) you can do
conta_pos(In, (_,V), Out) :-
aggregate(count, X^member((X,V), In), Out).
Result :
?- conta_pos( [(1,2), (3,4), (5,2), (4,2), (8,0)], (_,2), Out).
Out = 3.
Filtering elements matching (via unification) with a template, we have two recursive rules (one for when the element matches Z, and one for when the element does not match):
filter([X|Xs],Z,[X|Ys]) :- % X is part of the output
copy_term(Z,E), % copy free variables (e.g. the _ in (_,2))
E=X, % matches with template Z
filter(Xs,Z,Ys). % recurse
filter([X|Xs],Z,Ys) :- % X is not part of the output
copy_term(Z,E), % copy free variables
E\=X, % does NOT match with template Z
filter(Xs,Z,Ys). % recurse
filter([],_,[]). % base step
We have to use copy_term/2 to generate a new copy of free variables, otherwise it will ground the matching variables at the first step and try to match the grounded template against the remaining elements, and would fail.
?- filter([(1, 2), (3, 4), (5, 2), (4, 2), (8, 0)], (_, 2), Y), length(Y, Count).
Y = [(1, 2), (5, 2), (4, 2)],
Count = 3
Alternatively, you can directly count the matching elements with a recursive predicate, which works exactly the same as the previous solution:
count([X|Xs],Z,Count) :-
copy_term(Z,E),
E=X,
count(Xs,Z,Count1),
Count is Count1 + 1.
count([X|Xs],Z,Count) :-
copy_term(Z,E),
E\=X,
count(Xs,Z,Count).
count([],_,0).
Test:
?- count([(1,2), (3,4), (5,2), (4,2), (8,0)], (_,2), Count).
Count = 3
The two recursive rules can be merged into one, with the conditional (->) operator:
count([X|Xs],Z,Count) :-
copy_term(Z,E),
count(Xs,Z,Count1),
( E=X -> Count is Count1 + 1 ; Count=Count1 ).
count([],_,0).
Related
I am new to prolog and trying to make a predicate to separate a list in to atoms and integers but I have been try different ways for a while now but no where is there is an example on how this would be done. To me this seems like a basic thing to know in proleg yet there is no example that I can find on how this would be done.
eg:
separate([3,t,8,l,0,a,5,g,2],Atoms,Integers). Atoms = [a,g,l,t], Integers = [0,2,5,3,8]
In swi-prolog, using partition/4:
separate(List, Atoms, Integers):-
partition(integer, List, Integers, Atoms).
This assumes that every item in the list is either an integer or an atom
Sample run:
?- separate([3,t,8,l,0,a,5,g,2],Atoms,Integers).
Atoms = [t, l, a, g],
Integers = [3, 8, 0, 5, 2].
Especially if you're learning, roll your own. This also allows you to handle the edge cases. This, for instance, simply discards things other than atoms and integers:
atoms_and_ints( [] , [] , [] ) . % The empty list doesn't have any atoms or ints.
atoms_and_ints( [X|Xs] , [X|Atoms] , Ints ) :- % For a non-empty list,
atom(X), % - is the head an atom?
!, % - eliminate the choice point
atoms_and_ints(Xs,Atoms,Ints). % - add it to the atoms and recurse down.
atoms_and_ints( [X|Xs] , Atoms , [X|Ints] ) :- % Similarly,
integer(X), % - is the head an integer?
!, % - eliminate the choice point
atoms_and_ints(Xs,Atoms,Ints). % - if so, add it to the Ints and recurse down.
atoms_and_ints( [_|Xs], Atoms, Ints ) :- % If the head of the list is something else...
atoms_and_ints(Xs,Atoms,Ints). % - discard it and recurse down.
I need to get each index of all positive elements in the list and create a new list with all of these indexes
For example,
[-1,2,-5] -> [1]
[1,2,-5] -> [0,1]
I've already had a predicate to get index, but I do not understand how to iterate through each value and return a list at the end. Right now my predicates looks like
indexOf([Element|_], Element, 0) :- !.
indexOf([_|Tail], Element, Index) :-
indexOf(Tail, Element, Index1),
!,
Index is Index1+1.
iterate([],Res) :- Res.
iterate([H|T],Res) :-
H>0,
indexOf([H|T],H,Ind),
append([],[Ind],Res),
iterate(T,Res).
iterate([H|T],Res) :-
H=<0,
iterate(T,Res).
But after compilation, I receive this error
**Input**
iterate([-1,-2,3],X).
**Output**
Sandbox restriction!
Could not derive which predicate may be called from
call(C)
iterate([],A)
iterate([3],A)
iterate([-2,3],A)
iterate([-1,-2,3],A)
Pls, tell me, what I'm doing wrong? And why this error appears
You are using Prolog wrongly:
iterate([],Res) :- Res.
will call the term bound to Res (hopefully the name of a predicate), but not return Res.
SWISH will not let you perform wild calls about which it cannot determine that they are safe, hence the error.
But why such complex code? Do as specified:
% ---
% gimme_positives(List,Positive)
% gimme_positives_2(Idx,List,Positive)
% ---
% We call this
gimme_positives(List,Indexes) :-
gimme_positives_2(0,List,Indexes).
% This is the "helper" which additionally needs an index
gimme_positives_2(_,[],[]). % If List empty, we are done.
gimme_positives_2(Idx,[L|Ls],[Idx|More]) :- % Case of L positive
L >= 0,
IdxPlus is Idx+1,
gimme_positives_2(IdxPlus,Ls,More). % recursive call
gimme_positives_2(Idx,[L|Ls],More) :- % Case of L negative
L < 0,
IdxPlus is Idx+1,
gimme_positives_2(IdxPlus,Ls,More). % recursive call
Then:
?- gimme_positives([],X).
X = [] ;
false.
?- gimme_positives([-1,2,-5],X).
X = [1] ;
false.
?- gimme_positives([1,2,-5],X).
X = [0,1] ;
false.
This is actually a case for foldl/4 ... once you feel at home with higher-order predicates and composing lists:
gimme_positives_foldl(List,Indexes) :-
foldl(
selector,
List, % the list of integers
[0,Indexes], % the initial value: index 0 as first, and the RESULT list as second element
[_FinalIndex,[]]). % the final value: an index we don't care about and the termination of the result list: []
selector(L,[Idx,[Idx|More]],[IdxPlus,More]) :-
L >= 0,
IdxPlus is Idx+1.
selector(L,[Idx,More],[IdxPlus,More]) :-
L < 0,
IdxPlus is Idx+1.
I can't even fully explain why I write the above like that.
But it works:
?- gimme_positives_foldl([],X).
X = [].
?- gimme_positives_foldl([-1,2,-5],X).
X = [1] ;
false.
?- gimme_positives_foldl([1,2,-5],X).
X = [0,1] ;
false
In SWI-Prolog, you can use the predicates nth0/3 and findall/3:
positive_element_indexes(List, Indexes) :-
findall(Index,
(nth0(Index, List, Element), Element > 0),
Indexes).
Some examples:
?- positive_element_indexes([1,-2,3,-4,5], Indexes).
Indexes = [0, 2, 4].
?- positive_element_indexes([-1,-2,3], Indexes).
Indexes = [2].
?- positive_element_indexes([-1,2,3], Indexes).
Indexes = [1, 2].
?- positive_element_indexes([-1,-2,-3], Indexes).
Indexes = [].
I'm working on creating a board used for the Bert Bos puzzle, and I'm trying to represent the board as a list of lists.
I need to create a list of empty lists ex [ [], [] , [] , [] ] but the problem is I need the exact number of empty lists provided from the input. So for example if I give create_board(4,X), it should return X= [ [], [], [], [] ].
Here is what I have so far
generate_board(0, [[]]) :- !
generate_board(N, [[] | T]) :-
N =< 12, N >= 1,
N is N-1.
generate_board(N, T).
An easy way to create a list of a given length consisting of the same element, or just empty lists in this case, is to use maplist2:
generate_board(Length, Board) :-
length(Board, Length),
maplist(=([]), Board).
Here, maplist(=([]), Board) will call =([], Element) (the canonical form of [] = Element) for each Element in Board, thus unifying each element with []:
| ?- generate_board(4, L).
L = [[],[],[],[]]
yes
| ?-
You can extend this concept to do a two-dimensional empty board. Think of the board as a list of rows (with length Length) and each row as a list of elements (with length Width):
generate_board(Length, Width, Board) :-
length(Row, Width),
maplist(=([]), Row), % A row of empty lists, forming an empty row
length(Board, Length),
maplist(=(Row), Board). % A list of empty rows
| ?- generate_board(4,3, L).
L = [[[],[],[]],[[],[],[]],[[],[],[]],[[],[],[]]]
yes
| ?-
Here is just the reason why your program did not work (apart from the . in place of ,). Because this fragment fails, also your original program fails. You have to generalize the visible part somehow.
:- op(950,fy,*).
*_.
generate_board(0, [[]]) :- !
generate_board(N, _/*[[] | T]*/) :- % 2nd
* N =< 12, % 2nd
* N >= 1, % 2nd
N is N-1,
* generate_board(N, T). % 1st generalization
?- generate_board(4, B).
This method works for pure, monotonic Prolog programs. You have, however, used a cut which restricts generalization. In this case, one really has to pay attention not to generalize anything prior to the cut. The first generalization is thus the recursive goal. It is the very last goal in the clause. Only then, the other generalizations may take place
In your program without the cut, we could have generalized your program even further:
generate_board(0, _/*[[]]*/).
...
A simple solution:
generate_board(N, Board) :-
findall([], between(1, N, _), Board).
Apart from a couple of syntax errors, the main problem with your code is the line N is N-1. In Prolog, you cannot 're-assign' a variable. A variable has a single value throughout a predicate. 'N is N-1` can only succeed for a value which is equal to itself minus 1, which will obviously never be the case.
Fixing it is simple: just use a different variable for the reduced value:
generate_board(0, [[]]) :- !.
generate_board(N, [[] | T]) :-
N =< 12, N >= 1,
N2 is N-1,
generate_board(N2, T).
?- generate_board(4, X).
X = [[], [], [], [], []]
This gives a result, but it's one more element than intended. Can you figure out how to fix this yourself (hint: look at what the base case returns for input 0)
I have a list of atoms in Prolog, and a predicate allowed(X, Y) that checks whether a pair of items is allowed. How can I take the list and split it into pairs of items, each of which satisfies the predicate? Ideally the pairs would be generated randomly and then checked, but this is only desired.
It can be assumed that the list has an even number of items.
pair(L1,L2,(M1,M2)) :-
member(M1,L1),
member(M2,L2).
Will retrieve, on backtracking, each possible pair. For example:
?- pair([1,2,3],[a,b],X).
X = (1, a) ;
X = (1, b) ;
X = (2, a) ;
X = (2, b) ;
X = (3, a) ;
X = (3, b).
?-
May be used on a single list, too:
?- pair([1,2,3],[1,2,3],X)
However, your question is pointless since all allowed pairs are predefined by allowed/2. You may just retrieve all solutions to allowed/2. So, this is what you are looking for, I guess:
allowed_pair(List,(A,B)) :-
allowed(A,B),
member(A,List),
member(B,List).
For example, provided that allowed/2 was defined as:
allowed(1,b).
allowed(2,a).
Then:
?- allowed_pair([1,2,3,a,4,z],X).
X = (2, a) ;
false.
?-
Depending on your performance requirements and allowed/2 implementation, you may exchange order of allowed_pair/2 goals.
I ended up doing it as follows:
checked(_, _, _, N) :-
N > 5,
fail.
checked(List, ReturnedList, [X,Y], _) :-
random_member(X, List),
select(X, List, List1),
random_member(Y, List1),
allowed(X, Y),
select(Y, List1, ReturnedList).
checked(A, B, C, N) :-
checked(A, B, C, N+1).
pairMe([], []).
pairMe(List, Result) :-
checked(List, ReturnedList, [X,Y], 0),
pairMe(ReturnedList, A),
append([[X,Y]], A, Result).
It's not great, as it doesn't guarantee that it'll always find a result even if one exists, but it works for me at least.
Basically, I need to write a predicate, even_elts(L,M), such that L is a new list generated that contains only the even indexed elements from M (0th, 2nd, 4th, etc)
add_tail([X],[],X).
add_tail([H|NewT],[H|T],X) :-
add_tail(NewT,T,X).
even_elts(L,[]) :- L = [].
even_elts(L,M) :- even_elts2(L,M,1).
even_elts2(L,[H2|T2],Ct) :-
Ct2 is Ct + 1,
((Ct2 mod 2) =:= 0, add_tail(L,L2,H2), even_elts2(L2,T2,Ct2); even_elts2(L,T2,Ct2)).
even_elts2(_,[],_) :- !.
This works if M is empty or contains 1 or 2 elements. But, it only gets the first even indexed element from M, not the rest. Any pointers
EDIT: Solved the problem a different way, by removing the odd indexed elements rather than trying to create a new list and copying the data over. But, if someone can figure out a solution for my original code, I would be interested to see.
You're making this much more complicated than it is. You can use pattern matching to get each even element out, then collect those in the second (output) argument.
% an empty list does not have even elements
even_elts([], []).
% for all other lists, skip the second element (_),
% add the first to the output, recurse
even_elts([X, _ | L], [X | R]) :-
even_elts(L, R).
Just another approach with accumulator:
even_elts(L,M) :-
even_elts(M,0,[],L).
even_elts([H|T],I,Acc,Ans) :-
( I mod 2 =:= 0, append(Acc,[H], AccNew)
; I mod 2 =:= 1, AccNew = Acc
),
Inew is I + 1,
even_elts(T,Inew,AccNew,Ans).
even_elts([],_,Acc,Acc).
And
?- even_elts(X,[1,2,3,4,5]).
X = [1, 3, 5] ;
evens([A,B|C], [A|D]):- !, .....
evens(X, X).
is all you need. Fill in the blanks. :)