Question

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
Was it helpful?

Solution 2

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.

OTHER TIPS

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] ? ;

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top