I searched around and couldn't find the answer. I'm having trouble making a genealogy list.
So, I have some is_a relations, for example:
is_a(cow, animal).
is_a(calf, cow).
is_a(dog, animal).
.... etc.
I want to have a procedure that does the following:
toAnimal(cow, X).
that outputs
X= [calf, cow, animal].
Basically, if I give it an input(cow), then it will go from cow until animal and add every step to the list.
So far, I have this:
toAnimal(A, B) :- is_a(A,B).
toAnimal(A, B) :- is_a(A, X), toAnimal(X, B).
The output of this is would be
X= cow;
X = animal;
false
How would I get this to become a list?
EDIT:
descend(X,Y) :- is_a(X,Y).
descend(X,Y) :- is_a(X,Z), descend(Z,Y).
toAnimal(X,Y):-
findall(X, descend('animal', X), Y).
I have updated it to this after looking at the suggestion. However, how do I get the list to print? I'm still new to prolog. The findall page said that it would return the list, but it is not doing so for me.
toAnimal(calf, Y)
outputs:
false.
EDIT:
It now returns an empty list. I'm not sure what the issue is here. I have not changed the code at all, so the output should not change but it has.
EDIT:
Thanks MrBratch for the response.
I made the suggested changes, but I now have another issue.
For example,
if I have the relations:
is_a(calf, cow).
is_a(calf, animal).
is_a(cow, cool).
is_a(cool, awesome).
But I ONLY want the path from calf to awesome.
The code will give me the ALL possible paths from calf,x.
For example,
descend(X,Y) :- is_a(X,Y).
descend(X,Y) :- is_a(X,Z), descend(Z,Y).
toAwesome(A,Y) :-
findall(X, descend(calf, X), Y).
will give me a list Y that has
[cow,animal,cool,awesome].
but what I want is
[calf,cow,cool,awesome].
How do I filter the other paths?
and also add the starting point? I suppose I can append calf to the beginning as the head, but how do I ignore the other paths?
EDIT:
Thanks for the help
I figured it out, but I lose the end path and start path. For example,
L contains cow,cool.
But calf and awesome are not there. I tried appending but I don't really understand the syntax. I'm not allowed to do append(X,L,anewlist)?
descend(X,Y) :- is_a(X,Y).
descend(X,Y) :- is_a(X,Z), descend(Z,Y).
toAnimal(A,B) :-
setof(X, (descend(A,X), descend(X,'awesome')), B).
--> append(A, L,anewlist).
?? Is this line not allowed here? How else would I do it? or is there a simpler way to just add it from the beginning
Here it is. (NOTE: you don't need descend predicate to figure out the path of a particular branch of the tree)
is_a(calf, cow).
is_a(calf, animal).
is_a(cow, cool).
is_a(cool, awesome).
path(X,Y,[Z|T]) :- \+ is_a(X,Y), is_a(X,Z), path(Z,Y,T).
path(X,Y,[Y]) :- is_a(X,Y).
find_path(X,Y,[X|L]) :- path(X,Y,L).
Usage:
| ?- find_path(calf,awesome,L).
L = [calf,cow,cool,awesome] ? ;
This sample more or less does what you want:
is_a(cow, animal).
is_a(calf, cow).
is_a(dog, animal).
is_a(snoopy, dog).
is_a(lassie, collie).
is_a(collie, dog).
toAnimal3( X, [X,animal] , animal ):- is_a( X, animal).
toAnimal3( X, [X|R], R ):- is_a( X, Y), toAnimal3(Y, R, _).
:- initialization(main).
main :- toAnimal3( lassie, A, B), write(A), write(B).
When run, this is the output:
[lassie,collie,dog,animal][collie,dog,animal]
Tested it online using this Prolog online interpreter
POST EDIT: Ah, that was it! I should've written "[X,animal]" instead of "[X|animal]" for the first clause! Thanks galore to #mbratch , now the program does exactly what was intended.
toAnimal(X,Y) :- setof(X, descend('animal', X), Y). should do it. Or findall/3.
Info and some examples of bagof, setof, findall.
But remember that you are asking for descend(animal, X) so it won't match the fact is_a(dog, animal) for example, which descend(X, animal) will. You need to make descend to search both sides, or simply be sure that your is_a facts say animal just on left side.
If you want to filter you could do
toAnimal(X,Y) :- setof(X, (descend('animal', X), not(X = animal)), Y).
but you are getting animal as a result because what I mentioned before.
Related
my code in prolog
:- dynamic kitchenfurniture/1.
kitchenfurniture([furniture(fridge,1), furniture(table,2), furniture(chair,1)]).
writel([H|T]) :- write(H), nl, writel(T).
whatkitchenfurniture :- kitchenfurniture(X), writel(X).
addkitchenfurniture(X) :- kitchenfurniture(Y), append(Y, [X], Z), retract(kitchenfurniture(Y)), assert(kitchenfurniture(Z)).
deletekitchenfurniture(X) :- kitchenfurniture(Y), delete(X, Y, Z), retract(kitchenfurniture(Y)), assert(kitchenfurniture(Z)).
when I enter the code in the console
it does not remove the item from the list
problem wth line code deletekitchenfurniture(furniture(fridge,1)).
It is difficult to understand what exactly you type into the console; why don't you show it?
It is probable that this is wrong:
?- deleteaddkitchenfurniture('furniture(fridge,1)').
The correct way to do it might be:
?- deleteaddkitchenfurniture(furniture(fridge,1)).
No single quotes there. If you put it in single quotes, it becomes an atom with some parentheses embedded in it. If you don't quote, it is a compound term, as in the original list you have in here:
kitchenfurniture([furniture(fridge,1), furniture(table,2), furniture(chair,1)]).
I want to create a predicate in Prolog which will check if a list A is a sublist of a list B. Moreover I do not want my program to consider an empty list as a subset of another one.
E.g. included_list([1,4],[1,2,3,4,5]).
true.
included_list([2,3],[1,2,3,4,5]).
true.
included_list([1,6],[1,2,3,4,5]).
false.
included_list([],[1,2,3,4,5]).
false.
and so on...
So, I have written the following code so far:
member(X,[X|Tail]).
member(X,[Head|Tail]):- member(X,Tail).
included_list([X],_).
included_list([Head|Tail],List):- member(Head,List), included_list(Tail,List).
But the above code seems to be wrong, because in one specific case it throws true, instead of throwing wrong. I wish I'd made it clear having presented the following screenshot:
As you might have noticed the fifth(5th) sentence gives true, instead of wrong. That is, when I write a sentence of the form:
included_list([x,y],[w,x,v,z]).
whereas only x is included in the second list(and not y) the program gives me true(and this is wrong).
In general, if the first argument of the first list is included in the second list then, no matter if the rest of the former are included in the latter, the program gives me true.
In any other case the program gives me the right result(true or false).
What do I do wrong?
I will be waiting for your answers!
Thank you in advance!
Your problem is the first clause of included_list/2. This:
included_list([X], _).
What does it mean? It means, "If the first argument is a list with one element, succeed, ignoring the second argument."
A short aside: if you would not ignore compiler warnings, you would have caught this mistake already. You should get a loud and clear "Singleton variable" warning, hinting that the code you have written does not do what you think it does.
What you actually mean is more along the lines of:
subset_list([X|Xs], Ys) :-
subset_list_1(Xs, X, Ys).
subset_list_1([], X, Ys) :-
member(X, Ys).
subset_list_1([X|Xs], X0, Ys) :-
member(X0, Ys),
subset_list_1(Xs, X, Ys).
But I don't know why you don't simply use the available subset/2, and simply add a requirement that the subset is not an empty list:
subset_list(Subset, List) :-
Subset = [_|_], % a list with at least one element
subset(Subset, List).
Despite what the documentation claims, the second argument to subset/2 does not have to be a true "set", but it does expect that both lists are ground (do not contain any free variables). You can see the source code here.
In this answer we let meta-predicate maplist/2 handle recursion and define:
all_included(Sub, Es) :-
same_length(Es, Xs),
Sub = [_|_], % minimum length: 1
append(_, Sub, Xs), % maximum length: as long as `Es`
maplist(list_member(Es), Sub).
Let's run the queries the OP gave!
First up, use-cases we expect to succeed:
?- member(Xs, [[1,4],[2,3],[2,3,5],[3,4]]), all_included(Xs, [1,2,3,4,5]).
Xs = [1,4]
; Xs = [2,3]
; Xs = [2,3,5]
; Xs = [3,4]
; false.
Next up, some use-cases we expect to fail:
?- member(Xs, [[],[2,6],[1,6]]), all_included(Xs, [1,2,3,4,5]).
false.
?- all_included([3,5], [1,2,5]).
false.
I need to get all list element in out side of the list using prolog.
['1','2','3',a,b,c] to become X='1','2','3',a,b,c
I need the result X as shown above.
is it possibile to get the result?
This will literally display what you're asking for (I'm assuming you're interested in the result strictly for display purposes).
print_list(L) :-
write('X='),
print_list_aux(L), !.
print_list_aux([H1,H2|T]) :-
print(H1),
write(','),
print_list_aux([H2|T]).
print_list_aux([X]) :-
print(X),
nl.
print_list_aux([]) :- nl.
Example:
?- print_list(['1', '2', a, b]).
X='1','2',a,b
true.
?-
If you use write/1 instead of print/1, you eliminate the quotes on the numbers in the output, so it would be: X=1,2,a,b.
I need to duplicate list in prolog.
I have list:
L = [a(string1,value1),a(string2,value2),a(string3,value3),a(string4,value4)].
Output will be: L = [string1, string2, string3, string4].
How can I do this?
I can copy whole list by code:
copy([],[]).
copy([H|L1],[H|L2]) :- copy(L1,L2).
I have tried something like:
copy2([],[]).
copy2([H|L1],[K|L2]) :- member(f(K,_),H), copy2(L1,L2).
But it does not work properly.
But I need only strings from my original list. Can anyone help?
pattern matching is used to decompose arguments: you can do
copy([],[]).
copy([a(H,_)|L1],[H|L2]) :- copy(L1,L2).
It is uncommon to use a structure a/2 for this purpose. More frequently, (-)/2 is used for this. Key-Value is called a (key-value) pair.
Also the name itself is not very self-revealing. This is no copy at all. Instead, start with a name for the first argument, and then a name for the second. Lets try: list_list/2. The name is a bit too general, so maybe apairs_keys/2.
?- apairs_keys([a(string1,value1),a(string2,value2)], [string1, string2]).
Here are some definitions for that:
apairs_keys([], []).
apairs_keys([a(K,_)|As], [K|Ks]) :-
apairs_keys(As, Ks).
Or, rather using maplist:
apair_key(a(K,_),K).
?- maplist(apair_key, As, Ks).
Or, using lambdas:
?- maplist(\a(K,_)^K^true, As, Ks).
Declarative debugging techniques
Maybe you also want to understand how you can quite rapidly localize the error in your original program. For this purpose, start with the problematic program and query:
copy2([],[]).
copy2([H|L1],[K|L2]) :-
member(f(K,_),H),
copy2(L1,L2).
?- copy2([a(string1,value1),a(string2,value2),a(string3,value3),a(string4,value4)], [string1, string2, string3, string4]).
false.
Now, generalize the query. That is, replace terms by fresh new variables:
?- copy2([a(string1,value1),a(string2,value2),a(string3,value3),a(string4,value4)], [A, B, C, D]).
false.
?- copy2([a(string1,value1),a(string2,value2),a(string3,value3),a(string4,value4)], L).
false.
?- copy2([a(string1,value1),B,C,D], L).
false.
?- copy2([a(string1,value1)|J], L).
false.
?- copy2([a(S,V)|J], L).
false.
?- copy2([A|J], L).
A = [f(_A,_B)|_C], L = [_A|_D]
; ... .
So we hit bottom... It seems Prolog does not like a term a/2 as first argument.
Now, add
:- op(950,fx, *).
*_.
to your program. It is kind of a simplistic debugger. And generalize the program:
copy2([],[]).
copy2([H|L1],[K|L2]) :-
member(f(K,_),H),
* copy2(L1,L2).
Member only succeeds with H being of the form [_|_]. But we expect it to be a(_,_).
How can I check if an element in the list is an empty list: [] ?
I've got the following:
display_degrees([A,B,C,D]):- write(B).
display_degrees([A,B,C,D]):- B==[], nl,write('has no degree'), nl, !.
When I enter in something like:
display_degrees([1,[],3,4]).
I just get: [] instead of 'has no degree'. Is my syntax wrong? Can I not add a clause to this predicate like this?
You're getting this behavior because proof search stops when a goal has succeeded. When you type
display_degrees([1,[],3,4]).
the first rule unifies, and it writes B. Since it was a success, it stops. You can ask Prolog to keep searching, and then it will find the second clause. In swipl, I get
?- [foo].
?- display_degrees([1,[],3,4]).
[]
true r % I type 'r' there
has no degree
true.
If you're just learning Prolog, I suggest you avoid the cut operator ! for some time. Also, doing IO is not the most intuitive thing. I would try some exercises with defining things like natural numbers and recursive functions. E.g., plus:
plus(z, X, X).
plus(s(X), Y, s(Z)) :- plus(X, Y, Z).
The problem with what you have is that the more general rule will fire first. You could switch the order:
display_degrees([A,[],C,D]) :- nl, write('has no degree'), nl, !.
display_degrees([A,B,C,D]) :- write(B).
I could just as well have written for the first predicate:
display_degrees([A,B,C,D]) :- B == [], nl, write('has no degree'), nl, !.
But the "shortcut" I show initially is more idiomatic for a Prolog predicate like this.
I kept the cut since you know you deterministically want one choice. The first rule will match if and only if the second list element is [].
| ?- display_degrees([1,[],3,4]).
has no degree
yes
| ?- display_degrees([1,2,3,4]).
2
yes
| ?-