I'm working on the very easy reverse list example in Prolog.
append(A, [], [A]).
append(A, B, [A|B]).
reverse([], ReversedList).
reverse([A,B], ReversedList) :-
reverse(B, TemporaryList),
append(A, TemporaryList, ReversedList).
append works correctly. However, when I call reverse the interpreter doesn't respond with a variable like append but instead it just write true or false.
Here's the log:
1 ?- consult('capitolo2'.pl). % file containing the code
2 ?- append(a, [b,c,d], L).
L = [a,b,c,d]. % ok, this works
3 ?- reverse([a,b,c], L).
false. % what? why that's not L = something?
The platform is SWI-Prolog 7.2 on Windows
append/3
Did you unit test it? Did it work properly? Your append/3 implementation is incorrect. The first clause
The first clause:
append( A , [] , [A] ).
simply creates a list of length 1 from its 1st argument (whatever it might be). Given that, if you said:
append( [1,2,3] , [] , X ) .
You'd get back:
X = [ [1,2,3] ]
A list of length 1, with the sole item it contains being the original 1st argument. The second clause is similarly incorrect:
append( A , B , [A|B] ).
Prepends the 1st argument โ whatever it might be, and in its entirety โ as the head of that list. Given that, if you said something like:
append( [1,2,3] , [a,b,c] , X ) .
You'd get back:
X = [ [1,2,3] , a , b , c ] .
A list of length 4, the first item of which is the original 1st argument.
Prolog is a descriptive language: you describe the solution and let the engine work things out. append/3 asserts that a list (the 3rd argument to append/3 represent the concatenation of the 1st argument and the 2nd argument.
Here is an implementation of append/3, simplified for clarity:
append( [] , RL , RL ) . % The concatenation of an empty left-hand list and a right hand list is the right hand list.
append( [LH|LT] , RL , CL ) :- % The concatenation of a non-empty left-hand list and a right-hand list is true IF:
CL = [LH|CT] , % - The left-hand head and the concatenation head are the same, AND
append( LT , RL , CT ) % - recursively, the concatenated tail represents the conconcatenation of the left-hand tail and the right-hand list.
. % Easy!
As you pop items off the left-hand list, it will eventually decompose into the terminating special case. This can be simplified to the classic implementation:
append( [] , RL , RL ) .
append( [LH|LT] , RL , [LH|CT] ) :- append( LT , RL , CT ) .
reverse/3
Similarly, your reverse/3 implemenation is incorrect. Your first clause:
reverse([], ReversedList).
pretty much says that pretty much anything is the reverse of the empty list. Since your ReversedList variable is never referenced, your Prolog implementation should at least throw a warning about singleton variables here. Many implementations make it an error.
Your second clause:
reverse([A,B], ReversedList) :-
reverse(B, TemporaryList),
append(A, TemporaryList, ReversedList).
says that the reverse of a 2-item list ([A,B]) is obtained by
reversing the 2nd item in the list (B), and
appending the 1st item (A) to that.
Not exactly a correct description of the solution. You might try something like
reverse( [] , [] ) . % The empty list is already reversed, what with it being atomic and all.
reverse( [H|T] , R ) :- % a non-empty list can be reversed by decomposing it into its head and tail, and
reverse(T,T1) , % - reversing the tail, and
append(T1,H,R) . % - appending the head to the now-reversed tail.
It's possible there are other problems, but
reverse([], ReversedList).
is almost surely not what you want here. The reverse of an empty list is an empty list, translates to
reverse([], []).
Additionally,
reverse([A,B], ReversedList)
is also probably not what you want. It is not a list with head A and tail B, but rather a 2-element list.
Related
How do I define an append function for a list of predicates?
Ex. of a list:
listMember( 10,
listMember( 8,
listMember( 0,
listMember( 9,
empty_member
)
)
)
)
Ex. of append call for instance:
append( 10, listMember(8, listMember(0, listMember(9, empty_member))), List )
edit: it just needs to handle appending one term
Prolog's list notation ([ a, b , ... ]) is just simple syntactic sugar on top of ordinary prolog terms. The empty list is denoted by the atom []; a non-empty list is denoted by the term ./2, where the first argument in the term is the head of the list, and the second the tail of the list, being either the empty list or a non-empty list (.(a,.(b,[])) being the actual representation of [a,b]).
See my answer here for a full explanation.
This is the canonical implementation of append/3:
append( [] , L , L ) .
append( [H|T] , L , [H|R] ) :- append(T,L,R) .
Eliminating the syntactic sugar gives you this:
append( [] , L , L ) .
append( .(H,T) , L , .(H,R) ) :- append(T,L,R) .
That should get you on your way.
Edited to add:
If you you just want to append a single item to a list, it's a simple matter of traversing the list. When you reach the end, you insert it. Something like (using normal list notation):
append_item( X , [] , [X] ) .
append_item( X , [Y|Ys] , [Y|Zs] ) :- append_item(X,Ys,Zs).
or, sans syntactic sugar,
append_item( X , [] , .(X,[]) ) .
append_item( X , .(Y,Ys) , .(Y,Zs) ) :- append_item(X,Ys,Zs).
Edited to note: As noted by #keldan-chapman in the comments, as of SWI Prolog v7+, lists are no longer ./2 for a non-empty list, and the atom [] for the empty list. As of SWI Prolog v7+, a non-empty list is denoted by '[|]'/2 and the empty list by "a special constant which is printed as []".
Go figure.
For details, see the SWI Prolog documentation at ยง 5.1, Lists Are Special.
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'm a beginner at prolog and I'm having trouble getting started with the following problem:
Define the predicate partstr/3, where the first argument is a list, that generates a list A of length L that you find consecutive in the first list.
You should be able to present all answers with backtracking.
E.g.:
?- partstr([1, 2 , 3], L, A).
If L = 2 then A = [1,2] and [2,3],
or if L = 2 then F=[1,2] and [2,3].
and so on...
I feel like you would use recursion to solve it, but I'm not sure where to start. I would really appreciate some tips on how to solve this because I feel like I'm getting nowhere.
The core of this problem is that you need a way to pull all the sublist of length N from a list, correct?
So...
Consider that append/3 can concatenate two lists: append( [a,b,c], [1,2,3], L) returns L as [a,b,c,1,2,3]. But it can also decompose a list into a prefix and a suffix, so
append( Pfx, Sfx, [a,b,c])
will, on backtracking, successively yield:
Pfx
Sfx
[]
[a,b,c]
[a]
[b,c]
[a,b]
[c]
[a,b,c]
[]
...and... length/2 can not only tell you the length of a list, but
can generate lists of a specified length populated with unique,
unbound variables, so length(L,3) returns [V1,V2,V3].
You can combine those to get the behavior you want:
partstr( Xs, N, SL ) :- % To get all the contiguous sublists of length N from Xs...
append(_,Sfx,Xs) , % - repeatedly get all possible suffixes of Xs, and...
length(SL,N) , % - construct an empty, unbound list of the desired length (N), and...
append(SL,_,Sfx) % - pull that prefix off the suffix
. % Easy!
That's one approach. I imagine that this is coursework and that your instructor likely would like you to roll your own solution from scratch.
To do that, we first need a predicate that will yield the source list, and on backtracking remove the head of the list. Something like:
suffix( Xs , Xs ) .
suffix( [_|Xs] , Sfx ) :- suffix(Xs,Sfx).
Then we need a way to grab the 1st n elements from a list, something like this:
take( _ , 0 , [] ) :- ! .
take( [X|Xs] , N , [X|Sfx] ) :- N1 is N-1 , take(Xs,N1,Sfx) .
Given those two...
partstr( Xs, N , SL ) :-
suffix(Xs,Sfx),
take(Sfx,N, SL )
.
You can even dispense with the suffix/2 predicate, thus, rolling its functionality into partstr/3 itself:
partstr( Xs , N , SL ) :- take(Xs,N,SL).
partstr( [_|Xs] , N , SL ) :- partstr(Xs,N,SL).
And that, I think, is the sweet spot: it is hard to beat 4 lines of code โ
partstr( Xs , N , SL ) :- take(Xs,N,SL) .
partstr( [_|Xs] , N , SL ) :- partstr(Xs,N,SL) .
take( _ , 0 , [] ) :- ! .
take( [X|Xs] , N , [X|Sfx] ) :- N > 0 , N1 is N-1 , take(Xs,N1,Sfx) .\
I want to remove the element in list1 when it is equal to element in list2.
The query and the expected output is:
filter( [[1,2,3],[1]] , [[1]] , X ).
X = [[1, 2, 3]] ;
filter( [[1,2,3],[1],[2,3,4],[2]] , [[1],[2]] , X ).
X = [[1, 2, 3],[2,3,4]] ;
What I have done right now is :
filter(_,[],_).
filter([A|B],[A|D],E):-
filter(B,D,E).
filter([A|B],[C|D],[A|E]):-
A\=C,
filter(B,D,E).
but it seems not right and gives the output like this:
11 ?- filter([[1,2,3],[1]],[[1]],X).
X = [[1, 2, 3]|_G488] ;
Can anyone help? Maybe I was near success.
Your program will not work correctly because you are removing one element from the second list each time. Also your base case (the first clause) should not be an uninstantiated variable (that is what is giving you the |_G488 in your output.
You have to iterate over the first list filtering the elements found in the second list, but not remove the elements of the second list.
For example:
filter([], _, []).
filter([Item|L1], L2, L3):-
(member(Item, L2) -> L4=L3;L3=[Item|L4]),
filter(L1, L2, L4).
The first clase is the base case of the recursion. It states that the output for an empty list would be an empty list.
The second clause checks to see if the first item of the input list is found on the second list. If it is found then it won't be added to the resulting list; otherwise it is added. Then it recursively calls itself with the rest of the input list.
But in no case it removes the elements from the second list.
Well, the lazy way would be to use the build-ins, findall/3 and member/2:
filter( Xs , Ys , Rs ) :-
findall( X , ( member(X,Xs), \+ member(X,Ys) ) , Rs ) .
which says to find all X such that X is a member of the list Xs and Xs is *not* a member of the listYs`.
Assuming your instructor wants you to come up with your own implementation, you probably first want to decompose your problem. You need to do two things:
Iterate over a list, removing items that are found in another list.
Given an item, determine whether it is contained in another list.
Both of these are simple. To determine if an item is contained in a list, you could say something like:
contained_in( X , [X|Ys] ) :- % if we find the item in the list,
! . % - we succeed and eliminate any alternatives.
contained_in( X , [_|Ys] ) :- % otherwise, we discard the head of the list,
contained_in(X,Ys) . % - and keep looking by recursing down.
The actual filtering is pretty simple, too:
filter( [] , _ , [] ) . % once the source list is exhausted, we're done.
filter( [X|Xs] , Ys , [X|R] ) :- % otherwise...
\+ contained_in(X,Ys) , % - if the current list item is not contained in the list of items to be removed,
! , % - cut off alternatives,
filter( Xs , Ys , R ) . % - add the current item to the result list and recurse down.
. %
filter( [_|Xs] , Ys , R ) :- % if the current list item IS contained in the list of items to be removed,
filter(Xs , Ys , R ) % - discard it and recurse down.
. % Easy!
Your filter is just subtract available with many Prolog systems (I've tested with B-Prolog, SWI-Prolog and ECLiPSe):
?- subtract( [[1,2,3],[1]] , [[1]] , X ).
X = [[1, 2, 3]].
?- subtract( [[1,2,3],[1],[2,3,4],[2]] , [[1],[2]] , X ).
X = [[1, 2, 3], [2, 3, 4]].
You can look at the sources of SWI-Prolog or ECLiPSe for implementation details.
I am trying to write a program which make the following:
?- g([2,3, [22,[3],9] ,4,[5],99],X).
X= [2,3,22,[3],9 ,4,5,99]
So it searches for lists in the given list and replace it by their elements without brackets [].
So I wrote this program:
The first block just searches for the first element in the list which is list
If there is no such element it returns [there_is_no_list].
first_list_in_the_list([],[there_is_no_list]):-!.
first_list_in_the_list([H|_],X):-is_list(H),X=H,!.
first_list_in_the_list([_|T],X):-first_list_in_the_list(T,X).
The first block works in prolog perfectly.
The second block just search in the list for an element X and then split the list into a two lists one is the list of all elements before X and the second is the elements after X.
splite_when_find_element([H|T],H,[],T):-!.
splite_when_find_element([H|T],X,F,G):-
splite_when_find_element(T,X,F1,G),append([H],F1,F).
it also works fine in Prolog.
and the third block is append, and it joins two list together in a new list.
append([],L,L).
append([H|T],L,[H|U1]):- append(T,L,U1).
and the last part is:
gg(L,L):-first_list_in_the_list(L,[there_is_no_list]),!.
gg(L,U):-first_list_in_the_list(L,X),
splite_when_find_element(L,X,F,G),gg(G,R),append(F,X,E),
append(E,R,U).
When I give a query [2,[3],5] I get also [2,[3],5] and I really don't understand why it does this.
A simple recursive solution will also work. Recursion is done by the head of the input list. In the non-trivial case, when the head is a list itself, we just append the rest of the flattened list to it. In the code below, it has not flattened Rest yet in append(H, Rest, Out), but it will be, after the recursive call of g(In, Rest). Cut after the append call ensures that backtracking won't consider the last case, where the head will appear in the output as-is.
% Base case, empty list.
g([], []).
% First recursive case: head is list.
% Append remaining elements to it.
g([H|In], Out):-
append(H, Rest, Out), !,
g(In, Rest).
% Second recursive case: head is not list.
% Will appear as-is in the output.
g([H|In], [H|Out]):-
g(In, Out).
also a DCG can do
lev, X --> [X], {is_list(X)}, lev.
lev, [X] --> [X], lev.
lev --> [].
test:
?- phrase(lev,[a,[b,c,[d]],e],L).
L = [a, b, c, [d], e] .
To flatten 1 level of a nested list, try something like this:
flatten1( Xs , Ys ) :- % to flatten a list
flatten1( Xs , [] , Ys ) , % - invoke the worker predicate
. %
flatten1( [] , T , R ) :- % if we get to to the empty list
reverse(T,R) % - just reverse the accumulator and we're done.
. %
flatten1( [X|Xs] , T , R ) :- % if the head of the list is unbound
var(X) , % - check for being a var
! , % - cut (to eliminate problems on backtracking
T1 = [X|T] , % - prepend the head of the list to the accumulator
flatten( Xs , T1 , R ) % - and recurse down
. %
flatten1( [[]|Xs] , T , R ) :- % if head of the list is an empty list, skip it
flatten1( Xs , T , R ) % - ignore it and recurse down
. %
flatten1( [[X|Ns]|Xs] , T , R ) :- % if head of the list is a non-empty list
X1 = [Ns|Xs] , % - prepend the tail of the sublist to the list
T1 = [X|T] , % - prepend the head of the sublist to the accumulator
flatten( X1 , T1 , R ) % - and recurse down
. %
flatten( [X|Xs] , T , R ) :- % if the head of the list is something else (except an unbound variable)
T1 = [X|T] , % - prepend the list head to the accumulator and
flatten( Xs , T1 , R ) % - recurse down
. %