Prolog on finding last element of a list with append - list

So i found a way of solving it from stackoverflow and it involves this answer:
last(X,Y) :-
append(_,[X],Y).
But i can't actually understand how this actually works.
If anyone can help me it would be really helpful.Thanks.

You can use append/3 [swi-doc] in several directions. You can for example pass a list, and look how two lists can append to that list. For example:
?- append(X, Y, [1,4,2,5]).
X = [],
Y = [1, 4, 2, 5] ;
X = [1],
Y = [4, 2, 5] ;
X = [1, 4],
Y = [2, 5] ;
X = [1, 4, 2],
Y = [5] ;
X = [1, 4, 2, 5],
Y = [] ;
false.
As you can see, there are five ways to construct that. For example with X = [] and Y = [1,4,2,5], or with X = [1] and Y = [4,2,5].
We thus define the predicate last/2 as:
last(X, L) :-
append(_, [X], L).
Notice the [X] as second parameter. We here thus specify that the second list should be a singleton list (a list with exactly one element). An empty list, or a list with two or more elements will not unify with [X].
The append/3 predicate will this aim to unify the second list with candidates like we have seen in the example. But only if the second list is an singleton list, it will match, in which case X is unified with the last element.

See the definition on the SWI-Prolog website.
One of the examples is:
?- append(X, [Last], [a,b,c]).
X = [a,b],
Last = c.
It means the Last is the single element in a list.
Think of the imperative way that X appends the "Last" to the end of the list. Then, it becomes the list [a,b,c].
Therefore, to define the last, we could:
mylast(Xs,Last):-
append(_,[Last],Xs). % doesn't care about the rest of the elements except the [Last]

Related

Splitting a list without creating an empty list in Prolog

split(L,X,Y):-append(X,Y,L).
creates 4 splits as follows:
X = [],
Y = [1, 2, 3] ;
X = [1],
Y = [2, 3] ;
X = [1, 2],
Y = [3] ;
X = [1, 2, 3],
Y = [] ;
I want to eliminate the empty list created during split and keep only combinations which do not have empty list that is
X = [1],
Y = [2, 3] ;
X = [1, 2],
Y = [3] ;
You can first specify the pattern for X and Y, by unifying these with a "cons":
split(L, X, Y) :-
X = [_|_],
Y = [_|_],
append(X, Y, L).
The advantage of using this approach, is that you will probably safe some cycles, since append/3 will not propose certain solutions that are empty lists, that then have to be filtered out.
In order to solve your problem, as said in the comments, you have to add a condition that checks if X or Y are empty, in this way:
split(L,X,Y):-
append(X,Y,L),
x\=[],
Y\=[].
Why the check is done after append/3? X = [] is true because X can be unified with [] when it is still uninstantiated. When you call split/3, initially X and Y are uninstantiated (if you use the tracer you can see something like _4604\=[]): X = [] succeds and so the negation fails and the program returns false if you put X\=[] and Y\=[] before append/3.
To better understand, i suggest you to read this article.

Prolog Choose 3 From List

I have create a prolog program which given a Number a List and Sublist will generate sublists containing N items in each. I am told this can be done with 1 fact and 2 rules. I am given the hint that I chose the first item or I dont which is confusing me. I have the base case and the first case but I hope someone can help me understand the second case.
choose(1, [H], [H]).
choose(N, [H,TL], [H|ST]) :- choose(Less1, TL, ST), Less1 is N-1.
So my third rule I want to choose the second item in the list
choose(N, [F,S|T], [S|ST]) :- choose(Less1, T, ST), Less1 is N-1.
My last rule however is unbalanced and the whole does not work. Any ideas are greatly appreciated!
While this previous answer by #madanasta should already point you in the right direction, we extend on it in this answer by using clpfd:
:- use_module(library(clpfd)).
We define n_from_chosen/3 like this:
n_from_chosen(0,_,[]).
n_from_chosen(N,[X|Es],[X|Xs]) :-
N #> 0,
N #= N0+1,
n_from_chosen(N0,Es,Xs).
n_from_chosen(N,[_|Es],Xs) :-
N #> 0,
n_from_chosen(N,Es,Xs).
Sample query:
?- n_from_chosen(2,[1,2,3,4],Xs).
Xs = [1,2]
; Xs = [1,3]
; Xs = [1,4]
; Xs = [2,3]
; Xs = [2,4]
; Xs = [3,4]
; false.
How about this more general query?
?- n_from_chosen(N,[1,2,3],Xs).
N = 0, Xs = []
; N = 1, Xs = [1]
; N = 2, Xs = [1,2]
; N = 3, Xs = [1,2,3]
; N = 2, Xs = [1, 3]
; N = 1, Xs = [2 ]
; N = 2, Xs = [2,3]
; N = 1, Xs = [3]
; false.
The idea behind the first two clauses is correct in principle. However:
The first clause is of no use when a sublist of length 1 must be found but the original list is not of length 1. This is problematic.
In the second clause, I assume you mean [H|TL].
Given these, a solution to your problem might be:
choose(1, [H|_], [H]).
choose(N, [H|TL], [H|ST]) :- Less1 is N - 1, choose(Less1, TL, ST).
choose(N, [_|T], L) :- choose(N, T, L).
An attempt to explain:
The first clause will generate a sublist of length 1 given any list with at least one element: It will simply unify the third argument with a single-element list containing only the head of the original list.
The second clause will handle cases when sublists of a length greater than 1 are requested, in which case it will unify the third argument with a list containing the head of the original list and a tail which, thanks to recursion, will be a sublist of the original list's tail of a length equal to the requested length minus 1.
The third clause will simply skip over the original list's head and will unify the third argument with a list which, thanks to recursion, will be a sublist of the original list's tail of the requested length.
Thanks to the third clause, Prolog will be able to provide alternative solutions for requested lengths either equal to or greater than 1.
Some results:
?- choose(2, [1,2,3,4], L).
L = [1, 2] ;
L = [1, 3] ;
L = [1, 4] ;
L = [2, 3] ;
L = [2, 4] ;
L = [3, 4] ;
false.
Note that you cannot use this to solve queries with an unbound length variable as you could using #repeat's solution. To achieve that in pure Prolog you would have to change the logic behind the second clause a bit:
choose(N, [H|TL], [H|ST]) :- choose(Less1, TL, ST), N is Less1 + 1.
This might also help clarify how recursion works in this case.
Hope this helps.
(Disclaimer: I am fairly certain that one can provide a far better explanation of how the above solution works (not to mention a better solution).)

Prolog Lists, Add 1 to tail of the list

I'm trying to add either 1 or 2 to numbers in a list in SWI-Prolog.
I've managed to add 1 or 2 to the head of the list however I'm having difficulties adding onto each element on the tail of the list. I don't want to add 1 or 2 to EVERY element at the same time just at separate times. I.e. If my input is
add([2,3,4], X).
I would like the possibilities of X to be the following:
X = [3,3,4]
X = [4,3,4]
X = [2,4,4]
X = [2,5,4]
X = [2,3,5]
X = [2,3,6]
My code at present is:
add([],[]).
add([H1|T1],[H2|T2]) :-
is(H2,+(H1,1)), T1=T2;
is(H2,+(H1,2)), T1=T2.
Obviously this only adds 1 or 2 onto the head of the list and not the tail. Therefore does anyone know how I may go about adding 1 or 2 onto the elements in the tail of my list?
First define a predicate addX/3 that will add X to one of the members of the first list:
addX([], [],_). % base case
addX([H|T], [H1 | T], X) :- H1 is H + X. % add to first element
addX([H|T], [H | T1], X) :- addX(T, T1, X). % or retain the first element and add to some element in the tail
Than using it define your add predicate as addX with X=1 or X=2:
add(L, R) :- addX(L, R, 1).
add(L, R) :- addX(L, R, 2).
Testing:
?- add([2,3,4], X).
X = [3, 3, 4] ;
X = [2, 4, 4] ;
X = [2, 3, 5] ;
X = [2, 3, 4] ;
X = [4, 3, 4] ;
X = [2, 5, 4] ;
X = [2, 3, 6] ;
X = [2, 3, 4].
sometime more verbose can be clearer:
add([],[]).
add([H1|T],[H2|T]) :-
H2 is H1+1.
add([H1|T],[H2|T]) :-
H2 is H1+2.
add([H|T1],[H|T2]) :-
add(T1,T2).
now alternatives are listed out, the last one just handles - recursively - the remaining elements
Anyway, your code is just missing a line:
add([],[]).
add([H1|T1],[H2|T2]) :-
is(H2,+(H1,1)), T1=T2;
is(H2,+(H1,2)), T1=T2;
H1=H2, add(T1,T2).
After comment, here is how to subtract and keep only positive values:
add([H1|T1],[H2|T2]) :-
H2 is H1-1, H2 > 0, T1=T2;
...

Taking a tree and making a list

I have written a program that can take a list and change it into a tree.
build_tree([X,Y],'Tree'(X,Y)) :- !.
build_tree([X|Y],'Tree'(X,Z)) :- build_tree(Y, Z).
If I want to reverse the process and take the tree and change it back into a list, how would I do this?
Note that your tree->list conversion isn't a function since trees may correspond to multiple lists:
?- build_tree([1, 2, 3], T).
T = 'Tree'(1, 'Tree'(2, 3)).
?- build_tree([1, 'Tree'(2, 3)], T).
T = 'Tree'(1, 'Tree'(2, 3)).
If you want a predicate that can generate all lists from a tree, remove the cut from build_tree and apply it with a variable first argument. If you want a deterministic conversion, write a new predicate tree_to_list.
Just curious, how would that deterministic version play out? Assuming there was only one possible list, from the tree, for example:
('Tree'('Tree'(nil, 2, nil), 5, 'Tree'(nil, 6, nil)).
Which gives: L = [5, 2, 6]
If you remove the cut from the first rule, your code it's ready to work in 'backward' mode:
?- build_tree([1,2,3,4],T).
T = 'Tree'(1, 'Tree'(2, 'Tree'(3, 4))) ;
false.
?- build_tree(X,$T).
X = [1, 'Tree'(2, 'Tree'(3, 4))] ;
X = [1, 2, 'Tree'(3, 4)] ;
X = [1, 2, 3, 4] ;
false.
flatten(leaf, []).
flatten(node(L, E, R), Ls) :-
flatten(L, Ls1),
append(Ls1, [E], Ls2),
flatten(R, Ls3),
append(Ls2, Ls3, Ls).
if you consider tree ass node(leaf,Element,leaf) for example
flatten(node(node(leaf,2,leaf),3,node(leaf,5,leaf)),X).
gives X=[2,3,5].
and if you wanna have bst
List to Tree.
insert(E,leaf,node(leaf,E,leaf)).
insert(E,node(L,N,R),T) :-
E >= N,
T=node(L,N,R1),
insert(E,R,R1).
insert(E,node(L,N,R),T) :-
E < N,
T=node(L1,N,R),
insert(E,L,L1).
list_to_tree(List,Tree) :-
list_to_tree(List,leaf,Trea2),
Tree=Trea2.
list_to_tree([],Tree,Tree).
list_to_tree([H|T],Tree,St):-
insert(H,Tree,R),
list_to_tree(T,R,St).

How do I turn the outputs of a function into a list?

I have a function that outputs names that fit a specific constraint. This function is fine.
But I need to use that function to make another function that turns the outputs of the former function into a list. Being a complete beginner with Prolog, I have no clue how to do this.
My problem is that I don't know how to iterate over the outputs to append it to an accumulator. The function which outputs names does so, then I press ";" or SPACE and it outputs the next answer until it's out of answers. I figure this means I have to make multiple calls to the function then append it. But I don't know how many times I need to call it, since I can't iterate over it like a list with [Head|Tail].
Here's what I have so far(although it's probably wrong):
%p1(L,X) determines if chemicals in List X are in any of the products and stores those products in L
p1(L,X) :- p1_helper(L,X,[]).
p1_helper(L,X,Acc) :- has_chemicals(A,X),append(Acc,[A],K),L=K, p1_helper(L,X,K).
function that outputs names with query has_chemicals(X,[List of Chemicals]).:
%has_chemicals(X,Is) determines if the chemicals in List Is are in the chemical list of X.
has_chemicals(X,Is) :- chemicals(X,Y), hc(Y,Is).
%hc(X,Y) determines if elements of Y are in elements of X.
hc(Y,[]).
hc(Y,[C|D]) :- isin(C,Y), hc(Y,D).
Any help is appreciated.
But I need to use that function to make another function that turns the outputs of the former function into a list. Being a complete beginner with Prolog, I have no clue how to do this.
findall(+Template, :Goal, -Bag):
Creates a list of the instantiations Template gets successively on backtracking over Goal and unifies the result with Bag.
For example, how to collect all odd numbers from 1 to 15:
odd( X ) :-
X rem 2 =:= 1.
We can get all that odds one-by-one.
?- between( 1, 15, X ), odd( X ).
X = 1 ;
X = 3 ;
X = 5 ;
X = 7 ;
X = 9 ;
X = 11 ;
X = 13 ;
X = 15.
And we can collect them into a list:
?- findall(X, (between( 1, 15, X ), odd( X )), List).
List = [1, 3, 5, 7, 9, 11, 13, 15].
I think you are looking for a way to capture the output of isin/2. Then you can use the builtin with_output_to/2, and combine it with findall/3, as suggested by other answers.
I encourage you to visit this page especially if you use swi-prolog.
There are 4 predicates that do what you want : findall/3, findall/4, bagof/3 and setof/3.
To summarize, here is the test predicate I'll be working with :
test(0, 3).
test(1, 3).
test(2, 5).
test(3, 4).
First, the simplest, findall/3 and findall/4 :
?- findall(C, test(X, C), Cs).
Cs = [3, 3, 5, 4].
?- findall(C, test(X, C), Cs, TailCs).
Cs = [3, 3, 5, 4|TailCs].
They just return all the alternatives, with duplicates, without sorting, without binding the other free variables, as a normal list for findall/3 and difference list for findall/4. both findalls predicates succeed when the list is empty.
Then, bagof. Basically, bagof/3 works as findall/3 but binds free variables. That means that the same query than above but with bagof/3 returns :
?- bagof(C, test(X, C), Cs).
X = 0,
Cs = [3] ;
X = 1,
Cs = [3] ;
X = 2,
Cs = [5] ;
X = 3,
Cs = [4].
By telling bagof/3 not to bind all the free variables, you obtain findall/3 :
?- bagof(C, X^test(X, C), Cs).
Cs = [3, 3, 5, 4].
Still you have to note that bagof/3 fails when the result is empty, where findall/3 doesn't.
Finally, setof/3. It's basically bagof/3 but with the results sorted and no duplicates :
?- setof(C, X^test(X, C), Cs).
Cs = [3, 4, 5].