Put the information from a leaf in a list - list

I want to write a program that puts the information from the leaves in a tree in a list. I tried doing this:
leaves(l(_), [_]).
leaves(b(B1, B2), [L]):- leaves(B1, [L1]), leaves(B2, [L2]). append(L1, L2, L).
But it gives me L=[_A]. Why is that?

There are several errors in your code, the correct code looks like this:
leaves(l(X), [X]).
leaves(b(B1, B2), L):- leaves(B1, L1), leaves(B2, L2), append(L1, L2, L).
I think the main problem was the use of _. It's an anonymous variable, it means “anything can be here”. And if you have it twice in one term, both _ are different variables.
Also, you have . before append instead of ,. My Prolog interpreter (SWI-Prolog) reported two warnings about singleton variables, you shouldn't ignore those.

Also, as you describe a list, consider using DCG notation:
leaves(l(L)) --> [L].
leaves(b(B1,B2)) --> leaves(B1), leaves(B2).
Usage: ?- phrase(leaves(Tree), Leaves).

debug your program with trace, that would execute your query step by step so you can see why the result is wrong. basically that variable given as list entries usually caused by singleton variables (declared but not used, i.e. instantiated) as svick has stated.

Related

SWI-prolog : how to make a circular list by using some facts

loop1(a).
loop1(b).
loop1(c).
loop1(d).
circular(d, a).
circular(b, c).
circular(b, d).
circular(a, b).
so when I call:
in_cycle(a, Cycle).
it will return:
[a,b,d,a]
if I call:
in_cycle(b, Cycle).
it will return:
[b,d,a,b].
however, if you call:
in_cycle(c, Cycle).
it will return:
false. (because no loop is included).
here is my try:
in_cycle(C,Cycle) :- circular(C,Cycle1),in_cycle(Cycle1,Cycle).
I know this predicate has very serious problem : it won't stop...I really want to know what kind of base case I should add so this predicate will stop ? Should i add a condition so prolog will stop when it find the same alphbet ?
It would be grateful if someone could help me!
-------updated-------
check([Y,_|Z]) :- check([Y|Z]).
in_cycle(C, [C]).
in_cycle(C, [C, C1|Cycle]) :- circular(C, C1),check([C,C1|Cycle]),
in_cycle(C1, [C1|Cycle]).
What is the shortest cycle you could have in your fact database? Would circular(a, a). be cycle [a]? Knowing what the shortest cycle is might help you find (one of) the finishing condition(s) for your predicate.
To be able to find a list, your predicate needs to build it. Your in_cycle/2 never mentions any lists. You need to use the [Head | Tail] construct somewhere in there to be able to add elements to a list.
You already know something about what your cyclical list looks like. The first and last element are the same, and they are the same as the symbol you're trying to find the cycle for. Use that information.
To be able to tell when you completed a cycle, you need to remember which symbol you started with. To be able to do that with recursion, you need to keep state. So you're going to need an additional predicate where you keep that state. E.g. something involving a predicate like in_cycle(Current_symbol, Cycle, Start_symbol). You can then call that from your in_cycle/2.
Let's have a look at your try:
in_cycle(C, Cycle) :-
circular(C, Cycle1),
in_cycle(Cycle1, Cycle).
You can use the trace command at the prompt to see what's happening: trace, in_cycle(a, X).
Press Space to step through your program. Press h for help, and a to exit. Use notrace. to get out of trace mode again.
As you step through this, you'll find that your predicate is nicely looping through the cycle, but at no point does the X ever become a list. That's bad.
Let's try and make this build a list. As I mentioned in point (3), you already know something about the list. The first element of the list is the same as the first argument to in_cycle. Even more, the second element of the list is the same as the element you'll find with circular/2. So we know a cycle has at least two elements. How about this?
in_cycle(First, [First, Next|Cycle]) :-
circular(First, Next),
in_cycle(Next, [Next|Cycle]).
If you trace this now, you'll see something is happening with X, but still not actually anything useful. Cycle remains a mystery and we're just looping through the facts forever. You need some end condition here. Let's try a simple one:
in_cycle(First, [First]).
in_cycle(First, [First, Next|Cycle]) :-
circular(First, Next),
in_cycle(Next, [Next|Cycle]).
Whoa! in_cycle(a, X) suddenly gives results! All possible lists using circular connections starting with a, it seems. That's not exactly what we want, but maybe we're getting closer?
One problem with this is that in_cycle(Next, [Next|Cycle]) is not actually correct!
If you do in_cycle(a, X), you already know that X should become [a, b, d, a], so filling those values into in_cycle(First, [First, Next|Cycle]), you get:
First = a
Next = b
Cycle = [d, a]
When you get to in_cycle(Next, [Next|Cycle]), that means it's in_cycle(b, [b, d, a]). But [b, d, a] is not a cycle! You need to be able to distinguish these two situations somehow. One way of doing that is to call a separate predicate like I mentioned in (4) to keep track of what your starting element was.
A node is in a cycle, if you can find a path back to that very node. Using path/4:
in_cycle(C, [C|Cs]) :-
circular(C, A),
path(circular, Cs, A,C).
Now, does this predicate terminate? How can we test this in a systematic manner? How can we ensure that we do not forget any special case? For pure, monotonic programs as this one, testing for termination is trivial1: Simply take the most general query! That is:
?- in_cycle(C, Cs).
C = d, Cs = "dabd" % [d,a,b,d]
; C = b, Cs = "bdab"
; C = a, Cs = "abda"
; false. % it terminates!
(See this answer how to get "bdab" in place of [b,d,a,b]).
What is so nice in Prolog is that above query constitutes a proof of termination. Each query you can pose is included in above query. And since the more general query already terminates, any more specific query will terminate too! Any!
And all of this holds even for any variable free facts for circular/2. However, this proof cannot be carried out so easily as the proof for a specific set of facts.
1 Note that trivial means belonging to the trivium.

Prolog: put recursive predicates into Variable

I'm beginner in prolog and I need to resolve the following exercise:
Write a 3-predicate prereqchain(P,Q,L) that, given two courses P and Q, returns in L a representation of all the steps on a prerequisite path from P to Q.
For example prereqchain(comp085,itec450,L) should give the answer
L=prerequisite(comp085, comp101,
prerequisite(comp101, comp281,
prerequisite(comp281, itec450))).
Basically, the knowledge data base stand for the prerequisite relationship between the degree's courses. My main problem is, How can I capture the recursive calls trace and put it into variable ? On the other hand, is not really all the trace, because I just need the calls where the variables was replaced with the values.
Thanks a lot!
What's your base case? It's going to look like this:
prereqchain(Start, End, prerequisite(Start, End)) :-
prerequisite(Start, End).
This gives you the following situation:
?- prereqchain(comp281, itec450, L).
L = prerequisite(comp281, itec450).
So this is the first thing you need, now what happens when you ask for prereqchain(comp101, itec450)? You need an inductive case that follows the rest of the chain:
prereqchain(Start, End, prerequisite(Start, Middle, Tail)) :-
prerequisite(Start, Middle),
prereqchain(Middle, End, Tail).

Finding a specific sequence of elements in a list, prolog

I have to write a predicate that takes a List and succeeds if the list contains elements "a, b, c"in that order anywhere in the list, other wise it fails. I am pretty lost on where to start(not looking for a solution, just a hint to the right direction).
Declarative wording
Almost always, when a Prolog task is formulated in a rather imperative way, the solution will be comparatively limited. This means that we typically can only use it in a few modes and directions, while other modes may even yield wrong results.
Therefore, I suggest to use more declarative wording.
You say:
a predicate that takes a list and succeeds if the list contains elements "a, b, c" in that order anywhere in the list, otherwise it fails.
That's a rather procedural way to look at this. Note that in Prolog, any argument can also be a logical variable, and thus there may not even be a list to "take". Instead, we expect the predicate to generate such lists in these cases!
Watch your wording! Very often, when you are able to express the task declaratively, an elegant and general Prolog solution will be straight-forward and often follows quite naturally from the task description.
Describing solutions
First, let us focus on what holds. There is no need to express what doesn't hold, because the predicate will not succeed anyways in such cases.
What do we want to describe?
Essentially, we want to describe lists of the form [...,a,b,c,...].
There are already some answers, with various drawbacks.
A pure way to do it uses the meta-predicate if_/3 from Indexing dif/2:
abc([X,Y,Z|Vs]) :-
if_((X=a,Y=b,Z=c), true, abc([Y,Z|Vs])).
Generality
This works in all directions. First, let us try the most general query, where the single argument is a fresh variable:
?- abc(Vs).
Vs = [a, b, c|_5032] ;
Vs = [a, b, a, b, c|_5144] ;
Vs = [a, b, a, b, a, b, c|_5286] .
Thus, we can generate solutions, which is a very nice property of a relation!
The predicate is monotonic, and therefore iterative deepening is possible to fairly enumerate answers:
?- length(Vs, _), abc(Vs).
Vs = [a, b, c] ;
Vs = [a, b, c, _11600] ;
Vs = [a, a, b, c] ;
Vs = [_11982, a, b, c],
dif(_11982, a) ;
Vs = [a, b, c, _11600, _11606] .
From this, it follows that there are no solutions with less than 3 elements. In this case, that's quite obvious. In other cases, such results may be much less obvious from the task description.
Efficiency
The predicate is deterministic if its argument is sufficiently instantiated.
For example:
?- abc([a,b,c]).
true.
?- abc([z,a,b,c]).
true.
?- abc([a,b,c,z]).
true.
Note that no choice points remain in these cases!
Here are three approaches you could take, in roughly ascending order by flexibility:
First, is to use the predicate nth0/3 to find the position of a, b, and c in the list, and then check that the position of a < position of b < position of c. For multiple instances of a, b, and c in the list (e.g. [c,b,a,b,c,a]) nth0 will find positions of each matching element in turn, such that if there are three positions that fit the criteria (even if they are not the first positions) the predicate will succeed.
Hint 1.1: The syntax for nth0 to find the position of a.
nth0(PositionA,[c,b,a,b,c,a],a)
Hint 1.2: The syntax of less than (for completeness)
PositionA < PositionB
Partial Solution 1: A sequence of commands using nth0 to check that a, b, and c appear in some order in the list [c,b,a,b,c,a] (assembling the predicate is left to you)
nth0(PositionA,[c,b,a,b,c,a],a),
nth0(PositionB,[c,b,a,b,c,a],b),
nth0(PositionC,[c,b,a,b,c,a],c),
PositionA < PositionB,
PositionB < PositionC.
Second approach uses list pattern matching - we observe that, when going down the list, we must encounter a, then b, then c. To do that, we can construct three predicates that find a, b, and c, and then pass on the rest of the list where appropriate. We must construct these predicates to ignore other elements until they see their target.
Hint 2.1: The head of a predicate where a is the first element of the list
find_a([a|Rest]) :-
Hint 2.2: The head of a predicate where anything is the first element of the list
find_a([_|Rest]) :-
Hint 2.3: When we find a, we start looking for b
find_a([a|Rest]) :-
find_b(Rest).
Hint 2.4: When we don't find a, we keep looking for a
find_a([_|Rest]) :-
find_a(Rest).
Hint 2.5: Order matters (kind-of)
If we place find_a([a|Rest]) first in the knowledge base then Prolog will always try to unify against it first, so we'll match the first a we find. If we place it second, this will still work, but with a lot of extra backtracking, and we'll find each a in reverse order.
Hint 2.6: Don't forget the base case!
Remember that, even though you don't need to do anything once you find c, you still need to create a fact stating that it is the head of the list: find_c([c|_]).
The third approach is essentially a generalised version of the second approach - instead of creating predicates to find a, b, and c, you create a predicate that finds a list of elements in order.
Hint 3.1: Your predicate should take two lists and compare the heads of each
compare([A|Targets],[B|Checks]) :-
Hint 3.2: If the same variable name appears in multiple places, it must have the same value for the predicate to match
compare([A|Targets],[A|Checks]) :- % succeeds when the same element is at the head of each list
Hint 3.3: If they match, keep going down both lists
compare(Targets,Checks).
Hint 3.4: If they don't match, only go down the Checks list
compare([A|Targets],Checks).
Hint 3.5: Never forget the base case (when there are no more targets)
compare([],_).
Hint 3.6: As before, ordering is still important
compare([A|Targets],[A|Checks]) :- ... should be in the knowledge base before compare(Targets,[_|Checks]) :- ...
Solution 3:
compare([],_).
compare([A|Targets],[A|Checks]) :-
compare(Targets,Checks).
compare(Targets,[_|Checks]) :-
compare(Targets,Checks).
Hope this helps!
Another way to describe the relation uses a grammar. You are talking about a sequence, well, that's what the dcg formalism is for!
:- set_prolog_flag(double_quotes, chars).
abcsubsequence(Cs) :-
phrase(abc, Cs).
abc -->
..., "abc", ... .
or alternatively, if you permit further text in between:
abc -->
..., "a", ..., "b", ..., "c", ... .
So what is this magic ...? It's just any sequence:
... --> [] | [_], ... .
Efficiency-wise mat's solution is much better. But for correctness reasons above versions are better since they fail for abcsequence([a,b,c|non_list]). However, making relations a tiny bit more general by permitting such solutions is quite common in Prolog, you just have to be aware of it.
Finding a,b,c
To find the letters a,b,c in a list in that order one should start with the comment by #lurker which says [X, Y, Z | T].
has_abc([a,b,c|T]).
Since I am using SWI-Prolog and prefer not to receive the warning
Warning: somecode.pl:
Singleton variables: [T]
I will make a small change by changing T to _
has_abc([a,b,c|_]).
and then run some simple test
?- has_abc([a,b,c]).
true.
?- has_abc([a,b,c,z]).
true.
?- has_abc([z,a,b,c]).
false.
As you can see the predicate has_abc can find a,b,c at the start of a list but not any place else.
Taking a list a part
In Prolog a list can be recursively deconstructed using [H|T]
deconstruct_list([Head|Tail]) :-
write('Head of list: '),write(Head),nl,
deconstruct_list(Tail).
and a few demonstration cases
?- deconstruct_list([]).
false.
?- deconstruct_list([a]).
Head of list: a
false.
?- deconstruct_list([a,b]).
Head of list: a
Head of list: b
false.
?- deconstruct_list([a,b,c]).
Head of list: a
Head of list: b
Head of list: c
false.
Putting the predicates together
Now combining the first two predicates for finding a,b,c and deconstructing a list gives us
has_abc([a,b,c|_]).
has_abc([_|T]) :-
has_abc(T).
and a few test cases
?- has_abc([]).
false.
?- has_abc([a]).
false.
?- has_abc([a,b]).
false.
?- has_abc([a,b,c]).
true .
?- has_abc([z,a,b,c]).
true .
?- has_abc([a,b,c,z]).
true .
?- has_abc([z,a,b,c,z]).
true .
Resolving the choice-point with a cut
Almost there. There is a small problem because for the true answers we had to press Enter to exit which indicates we have a choice-point.
A way to fix this is with a cut (!) which say that once we have an answer stop looking for more answers.
has_abc([a,b,c|_]) :- !.
has_abc([_|T]) :-
has_abc(T).
and a few test cases
?- has_abc([]).
false.
?- has_abc([a]).
false.
?- has_abc([a,b]).
false.
?- has_abc([a,b,c]).
true.
?- has_abc([z,a,b,c]).
true.
?- has_abc([a,b,c,z]).
true.
?- has_abc([z,a,b,c,z]).
true.
?- has_abc([d]).
false.
?- has_abc([d,e]).
false.
?- has_abc([d,e,f]).
false.
?- has_abc([d,e,f,g]).
false.
Notice that when running the test cases one did not have to press Enter to end the query.
Resolving the choice-point without a cut
See the answer by mat

Prolog Beginner: Reverse List only once

Assume I have two arbitrary lists that represent the first two items of a 3-place predicate:
[anna,berta,charlotte],[charles,bob,andy]
I want to match every item in a third list (the third item of the 3-place predicate) as follows:
[[anna,andy],[berta,bob],[charlotte,charles]]
Basically the items get matched in a sequentially reverse fashion. To match the items in a sequential manner, I've devised the following code:
match([],[],[]).
match([A|At],[C|Ct],[[A,C]|Dt]):-match(At,Ct,Dt).
But this would give me the following:
match([anna,berta,charlotte],[charles,bob,andy],X).
X=[[anna,charles],[berta,bob],[charlotte,andy]]
So I need to reverse the second list somehow. So far, I've altered the code as follows:
match([],[],[]).
match([A|At],[C|Ct],[[A,B]|Dt]):-reverse([C|Ct],[B|Bt]),match(At,Bt,Dt).
But this would continually reverse the second list with each pass. The result would look as follows:
match([anna,berta,charlotte],[charles,bob,andy],X).
X=[[anna,andy],[berta,charles],[charlotte,bob]]
Question:
How do I reverse the second list only ONCE, so the actual results match the desired ones? Or is my approach fundamentally flawed? I'm new to prolog and am currently stymied by this. Any help would be appreciated.
Do exactly what you say: Reverse the list once, and then use the reversed list.
lists_pairs(Ps1, Ps2, Pairs) :-
reverse(Ps2, RPs2),
pairs_keys_values(Pairs, Ps1, RPs2).
You can check out the source code of reverse/2 and pairs_keys_values/3 in any decent Prolog library to see how it is defined.
Sample query and answer:
?- lists_pairs([anna,berta,charlotte], [charles,bob,andy], Ps).
Ps = [anna-andy, berta-bob, charlotte-charles].
I leave converting such pairs to the non-sensible "pair as list" representation as an exercise.
The trick to solving problems that require you to apply a rule only once is to build an auxiliary rule which performs extra steps before and/or after invoking the recursive rule:
match(A, B, R) :- reverse(B, RevB), match_impl(A, RevB, R).
match_impl([], [], []).
match_impl([A|At], [C|Ct], [[A,C]|Dt]) :- match_impl(At, Ct, Dt).
match_impl/3 is your match/3 rule renamed to avoid conflicting with the "top" match/3 rule that includes an auxiliary step.
This is a small followup to #mat's answer.
To aid termination in some cases you could add a redundant same_length_as/3 goal like so:
lists_pairs(Ps1, Ps2, Pairs) :-
same_length_as(Ps1, Ps2, Pairs),
reverse(Ps2, RPs2),
pairs_keys_values(Pairs, Ps1, RPs2).
The auxiliary predicate same_length_as/3 can be defined like this:
same_length_as([],[],[]).
same_length_as([_|As],[_|Bs],[_|Cs]) :-
same_length_as(As,Bs,Cs).

Defining lists in prolog scripts

I am new to prolog programming and have been told in a tutorial to define a list of structures (in a script) so that I can query it as a database. However I find it impossible to define this list as a variable in a script. When I define a list such as
X=[a,b,c].
I just receive an error saying
No permission to modify static_procedure `(=)/2'
Does prolog not support defining variables such as this? I am using SWI-Prolog under linux.
In Prolog we speak of logical variables, to mean identity between literals.
That is, a program it's a set of rules that collectively state what's true about our literals, and that literals are uninterpreted. We write rules using variables to describe relations about individuals, and while trying to prove if our query can become true, Prolog binds variables as rules dictate.
A list it's just syntax sugar for a binary relation between a term (the head) and (note the recursion here) a list. Usually, when we speak of a database, we use facts (rules without a body, always true) that binds atomic literals.
So that tutorial probably expresses the task in different words than you report, or it's somewhat misleading. You could anyway store lists in your database as such:
mylist([a,b,c]).
and write your program like:
myprog(X) :- mylist(L), member(X, L).
Then you can query your program like:
?- myprog(X).
and Prolog, trying to prove myprog/1, attempt to prove mylist/1 and member/2...
To prove mylist(L) the variable L get bound to [a,b,c].
HTH
When you write
X = [a, b, c].
It's read as
=(X, [a, b, c]).
which is read as a definition of a fact concerning the =/2 predicate. A fact where any free variable would be equal to [a, b, c]. That is, you redefine =/2. That's obviously not what you intend!
You have to remember in Prolog that variables are scoped only locally, inside a predicate. What would work is:
main :-
X = [a, b, c],
% do stuff with X.
I use swipl under linux, to define a list in prolog.
mylist([element1,element2,elementn]).
Then you can query your program:
?- mylist(A).
no, you cannot do it like this. what are you basically writing is:
=(X,[a,b,x]).
and as the error says you cannot redefine =/2
what you could do is:
x([a,b,c]).
and when you want to use X:
...
x(X),
foo(X)
...
If Y = [a,b,c], after the function makeList(Y,F) function call, F = [a,b,c]
makeList(Y,F) :-
append(Y,[],X),
F = X.
e.g)
?- makeList([a,b,c],X).
X = [a,b,c].