I want to write a reverse/2 function. This is my code and I cannot figure out where the error is.
rev([]).
rev([H|T],X):-rev(T,X),append(T,H,_).
The output:
rev ([1,2,3,4], X).
false.
rev(?List1,?List2) is true when elements of List2 are in reversed order compared to List1
rev(Xs, Ys) :-
rev(Xs, [], Ys, Ys).
rev([], Ys, Ys, []).
rev([X|Xs], Rs, Ys, [_|Bound]) :-
rev(Xs, [X|Rs], Ys, Bound).
Output:
?- rev([1,2,3,4],X).
X = [4, 3, 2, 1].
?- rev([3,4,a,56,b,c],X).
X = [c, b, 56, a, 4, 3].
Explanation of rev/4
On call rev([X|Xs](1), Rs(2), Ys(3), [_|Bound](4))
[X|Xs](1) - List1, the input list in our case (we can either call rev(Z,[3,2,1]).)
Rs(2) - ResultList is a helping list, we start with an empty list and on every recursive call we push (adding as head member) a member from [X|Xs](1).
Ys(3) - List2, the output list (reversed list of List1)
[_|Bound](4) - HelpingList for bounding the length of Ys(3) (for iterating "length of Ys" times).
On every recursion call rev(Xs(5), [X|Rs](6), Ys(3), Bound(7)).,
we push head member X ([X|Xs](1)) to the front of Rs ([X|Rs](6)),
and iterating the next member of Ys (Bound(7),[_|Bound](4)).
The recursion ends when rev([](9), Ys(10), Ys(3), [](12)). is true.
Every [X|Xs](1) (now the list is empty [](9)) member moved in reversed order to Ys(10), we bounded the size of Ys(3) (using [_|Bound](4) and now it's empty [](12)).
Notice that append/3 - append(?List1, ?List2, ?List1AndList2).
was wrong used in your code, append(T,H,_) when H is not a List2 (it's the head member of the list).
Example use of append/2 and append/3:
?- append([[1,2],[3]],X). % append/2 - Concatenate a list of lists.
X = [1, 2, 3].
?- append([4],[5],X). % append/3 - X is the concatenation of List1 and List2
X = [4, 5].
You should not place a space between the functor name rev and the argument list. Usually this gives a syntax error:
Welcome to SWI-Prolog (threaded, 64 bits, version 7.7.1)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.
?- rev ([1,2,3],X).
ERROR: Syntax error: Operator expected
ERROR: rev
ERROR: ** here **
ERROR: ([1,2,3],X) .
Otherwise I think the rev/4 solution aims at a bidirectional solution. If you don't need this, and want to go for an accumulator solution that doesn't leave a choice point, you can try:
reverse(X, Y) :-
reverse2(X, [], Y).
reverse2([], X, X).
reverse2([X|Y], Z, T) :-
reverse2(Y, [X|Z], T).
Related
I am trying to implement a predicate that splits a list of integers in two given another predicate as an argument. The definition is given as follows:
split(P, L, L1, L2),
where:
P - predicate to split upon
L - list to split
L1 - result list of integers that return true on predicate check
L2 - result list of integers that return false on predicate check
I am trying to modify this code, that splits the list with hardcoded check whether the integer in question is bigger / smaller or equal to X (this works):
split(X, [], [], []).
split(X, [H|T], [H|L1], L2) :- H=<X, split(X, T, L1, L2).
split(X, [H|T], L1, [H|L2]) :- H>X, split(X, T, L1, L2).
For testing purposes, I copied a predicate from RosettaCode to check if the number is even as follows:
even(N) :-
(between(0, inf, N); integer(N) ),
0 is N mod 2.
And here is my modification of the above code, but it returns "Syntax error: Operator expected" on last two lines:
split2(P, [], [], []).
split2(P, [H|T], [H|L1], L2) :- P(H), split2(P, T, L1, L2).
split2(P, [H|T], L1, [H|L2]) :- \+ P(H), split2(P, T, L1, L2).
I think my error is in checking whether the predicate returns true or false, but can't find the appropriate way of doing so.
EDIT: Forgot to add my call for this:
?- split2(even,[2,7,4,8,-1,5],L1,L2)
You can't call a predicate like this, you need to use call:
?- A = between(0,3,1), A. % OK, because A can be evaluated as it is
A = between(0, 3, 1).
?- A = between, A(0,3,1). % won't work
ERROR: Syntax error: Operator expected
ERROR: A = between,
ERROR: ** here **
ERROR: A(0,3,1) .
?- A = between, call(A, 0, 3, 1). % OK, using call
A = between.
?- A = between(0, 3), call(A, 1). % Partial application
A = between(0, 3).
Keep in mind that there are already library predicates that do exactly what you are after, see library(apply), esp. include/3. You should also take a look at the implementation, as it is slightly different from what you are doing and doesn't leave choice points behind.
PS: Rearranging the arguments so that the input list is at the front is the first step towards making this deterministic. You also need to get rid of the choice point caused by the two clauses, the one with call(P,H) and the one with \+ call(P,H). You can do this with a ->, as in the SWI-Prolog library.
Or maybe you are not bothered by the choice points, or want to make a more general predicate. I am sure that there are solutions here on Stackoverflow on the Prolog tag.
I want to implement the following problem in prolog:
Given
L1=[1,2,3,4] and L2=[2,3,4]
calling a function named remove_list(L1,L2,L) will remove L2 from L1 .
So L will be [1].
But if the elements of the 2nd list are not in the same order as in L1 or more accurately the 2nd one is not a subset of the first List ,it wont remove anything.
SayL1=[1,2,3,4,5] and L2=[2,3,6] or L2=[2,6] or L2=[4,3,2] will result L=[1,2,3,4,5]
Any help will be highly appreciated.
Thanks in advance
You can build your predicate remove_list/3 using recursivity, which is an useful tool when dealing with lists in Prolog.
remove_list([], _, []).
remove_list([X|Tail], L2, Result):- member(X, L2), !, remove_list(Tail, L2, Result).
remove_list([X|Tail], L2, [X|Result]):- remove_list(Tail, L2, Result).
Consult:
?- remove_list([4,5,1,6,3], [1,4,7], L).
L = [5, 6, 3].
The idea is to copy every element in your original list "L1" to your final list "L", except when that element is member of the second list "L2".
Your base clause is your stop condition, when your original list "L1" is empty, in that case ignoring your list "L2", the result is always the same empty list. (You can't delete nothing from the empty list).
Your second clause, don't copy the element in the head of the list "L1" to the final list "L" if that element in the head is member of the list "L2", also make the recursive call to the predicate with the Tail of your list "L".
And the final clause, copy the element in the head of the list "L1" to the final list "L", and also make the recursive call to the predicate with the Tail of that list "L". We don't need the goal member/2 here, because we used a cut in the previous clause.
EDIT: This answer should only be considered if you want to remove items from the list "L1" contained in the "L2" list, regardless of the order. To remove the subset "L2" from set "L1", please use Lurker's solution or this other solution:
remove_list(L, [], L):- !.
remove_list([X|Tail], [X|Rest], Result):- !, remove_list(Tail, Rest, Result).
remove_list([X|Tail], L2, [X|Result]):- remove_list(Tail, L2, Result).
This new solution considers the order of the elements in list "L2", but not in the strict sense, ie, may be interspersed in the original list "L1", which does not violate the concept of "L2" being a subset of "L1".
[2,4] is a subset of the set [1,2,3,4,5,6], but [2,4,7] is not:
?- remove_list([1,2,3,4,5,6], [2,4], L).
L = [1, 3, 5, 6].
?- remove_list([1,2,3,4,5,6], [4,2], L).
false.
?- remove_list([1,2,3,4,5,6], [2,4,7], L).
false.
Now, given the fact that is desired to obtain the original set rather than the negative response in case that any of the elements from the original set can be removed, then we use an auxiliary predicate:
rm_subset(L1, L2, L):- remove_list(L1, L2, L),!.
rm_subset(L1, L2, L1).
Consult:
?- rm_subset([1,2,3,4,5,6], [4,2], L).
L = [1, 2, 3, 4, 5, 6].
?- rm_subset([1,2,3,4,5,6], [2,4], L).
L = [1, 3, 5, 6].
Another possible solution, using the delete/3 predicate:
remove_elements(L, [H|T], R) :-
delete(L, H, R1),
remove_elements(R1, T, R).
remove_elements(L, [], L).
| ?- remove_elements([4,5,1,6,3], [1,4,7], L).
L = [5,6,3] ? ;
no
| ?-
EDIT I just realized I completely misread the problem. Duh. If you want to maintain order of the "removed" list as stated, then Boris' comment is right on regarding append/3. append(A, B, C) means that if you take A and append B you get C, with element order preserved.
So, to restate the solution as requested:
remove_elements(L1, L2, L) :-
append(A, B, L1),
append(C, L2, A),
append(C, B, L).
In general, if you just want to delete multiple elements in a list from another list you can just use:
subtract(+Set, +Delete, -Result)
where set = unorderd list which can have some duplicated elements and
delete = list of element we want to delete from Set.
Ex:
subtract([1,3,5,6,4,2,3], [1,2,3], R).
R = [5, 6, 4].
I am trying to write prolog code that will delete all punctuation (.,!? etc) from all lists in a list of lists. This is what I have so far:
delete_punctuation(_,[],_).
delete_punctuation(Character,[List|Tail],Resultlist) :-
delete(List,Character,NewList),
delete_punctuation(Character,Tail,[NewList|Resultlist]).
whereas 'Character' will be 33 for ! or 46 for . and so on since I will be using this only on lists of character codes. (I know, that the function would actually work for other elements that I would like to delete from the lists too.)
The results I receive when asking:
delete_punctuation(33,[[45,33,6],[4,55,33]],X).
is just
|: true.
However, I want it to be:
|: X = [[45,6],[4,55]].
What do I need to improve?
For this problem, I'd tackle it by addressing the two sub-problems separately, namely:
Filter/exclude a character code from a single list;
Applying the solution to the above to a list of lists of character codes.
To this end, I'd approach it like this:
exclude2(_, [], []).
exclude2(Code, [Code|Xs], Ys) :-
!, % ignore the next clause if codes match
exclude2(Code, Xs, Ys).
exclude2(Code, [X|Xs], [X|Ys]) :-
% else, Code != X here
exclude2(Code, Xs, Ys).
Note that some implementations like SWI-Prolog provide exclude/3 as a built-in, so you mightn't actually need to define it yourself.
Now, to apply the above predicate to a list of lists:
delete_punctuation(_, [], []).
delete_punctuation(Code, [L|Ls], [NewL|NewLs]) :-
exclude(Code, L, NewL),
delete_punctuation(Code, Ls, NewLs).
However, again, depending on the implementation, a built-in like maplist/3 could be used to achieve the same effect without having to define a new predicate:
?- maplist(exclude2(33), [[45,33,6],[4,55,33]], X).
X = [[45, 6], [4, 55]] ;
false.
n.b. if you want to use all SWI built-ins, exclude/3 requires the test to be a goal, like so:
?- maplist(exclude(==(33)), [[45,33,6],[4,55,33]], X).
X = [[45, 6], [4, 55]] ;
false.
For a more general approach, you could even add all the codes you want to exclude (such as any and all punctuation character codes) to a list to use as the filter:
excludeAll(_, [], []).
excludeAll(Codes, [Code|Xs], Ys) :-
member(Code, Codes),
!,
excludeAll(Codes, Xs, Ys).
excludeAll(Codes, [X|Xs], [X|Ys]) :-
excludeAll(Codes, Xs, Ys).
Then you can add a list with all the codes to delete:
?- maplist(excludeAll([33,63]), [[45,33,6],[4,55,33,63]], X).
X = [[45, 6], [4, 55]] ;
false.
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.
I need to write a program in Prolog that should remove every second element of a list. Should work this: [1,2,3,4,5,6,7] -> [1,3,5,7]
so far I have this, but it just returns "false".
r([], []).
r([H|[T1|T]], R) :- del(T1,[H[T1|T]], R), r(R).
del(X,[X|L],L).
del(X,[Y|L],[Y|L1]):- del(X,L,L1).
This is pretty much Landei's answer in specific Prolog syntax:
r([], []).
r([X], [X]).
r([X,_|Xs], [X|Ys]) :- r(Xs, Ys).
The second predicate is not required.
Alternative solution using foldl/4:
fold_step(Item, true:[Item|Tail], false:Tail).
fold_step(_Item, false:Tail, true:Tail).
odd(List, Odd) :-
foldl(fold_step, List, true:Odd, _:[]).
Usage:
?- odd([1, 2, 3, 4, 5, 6, 7], Odd).
Odd = [1, 3, 5, 7]
The idea is to go through the list, while keeping "odd/even" flag and flipping its value (false -> true, true -> false) on each element. We also gradually construct the list, by appending those elements which have "odd/even" flag equal to true, and skipping others.
This fine answer by #code_x386 utilizes difference-lists and foldl/4.
Let's use only one fold_step/3 clause and make the relation more general, like so:
fold_step(X, [X|Xs]+Ys, Ys+Xs).
list_odds_evens(List, Odds, Evens) :-
foldl(fold_step, List, Odds+Evens, []+[]).
Sample queries:
?– list_odds_evens([a,b,c,d,e,f], Odds, Evens).
Evens = [b,d,f], Odds = [a,c,e]
?– list_odds_evens([a,b,c,d,e,f,g], Odds, Evens).
Evens = [b,d,f], Odds = [a,c,e,g]
Edit
Why not use one clause less and do away with predicate fold_step/3?
lambda to the rescue!
:- use_module(library(lambda)).
list_odds_evens(List, Odds, Evens) :-
foldl(\X^([X|Xs]+Ys)^(Ys+Xs)^true, List, Odds+Evens, []+[]).
Another possibility is to use DCGs, they are usually a worthwhile consideration when describing lists:
list_oddindices(L,O) :-
phrase(oddindices(L),O). % the list O is described by oddindices//1
oddindices([]) --> % if L is empty
[]. % O is empty as well
oddindices([X]) --> % if L has just one element
[X]. % it's in O
oddindices([O,_E|OEs]) --> % if L's head consists of at least two elements
[O], % the first is in O
oddindices(OEs). % the same holds for the tail
This is certainly less elegant than the solutions using foldl/4 but the code is very easily readable, yet it solves the task described by the OP and works both ways as well:
?- list_oddindices([1,2,3,4,5,6,7],O).
O = [1, 3, 5, 7] ;
false.
?- list_oddindices(L,[1,3,5,7]).
L = [1, _G4412, 3, _G4418, 5, _G4424, 7] ;
L = [1, _G4412, 3, _G4418, 5, _G4424, 7, _G4430] ;
false.
I have no Prolog here to try it out, and I got a little bit rusty, but it should be along the lines of
r([]) :- [].
r([X]) :- [X].
r([X,Y|Z]) :- R=r(Z),[X|R].
[Edit]
Of course pad is right. My solution would work in functional languages like Haskell or Erlang:
--Haskell
r [] = []
r [x] = [x]
r (x:_:xs) = x : (r xs)
In Prolog you have to "pull" the right sides into the argument list in order to trigger unification.
I just needed a function like this and took a more "mathematical" approach:
odds(Xs, Ys) :- findall(X, (nth1(I,Xs,X), I mod 2 =:= 1), Ys).
It doesn't work both ways like some of the other fine answers here, but it's short and sweet.