List 带列表的Prolog祖先

List 带列表的Prolog祖先,list,prolog,ancestor,genealogy,List,Prolog,Ancestor,Genealogy,我四处寻找,找不到答案。我很难列出家谱 因此,我有一些is_a关系,例如: is_a(cow, animal). is_a(calf, cow). is_a(dog, animal). .... etc. 我希望有一个执行以下操作的过程: toAnimal(cow, X). that outputs X= [calf, cow, animal]. 基本上,如果我给它一个输入(cow),那么它将从cow一直到animal,并将每个步骤添加到列表中 到目前为止,我有: toAnimal(A,

我四处寻找,找不到答案。我很难列出家谱

因此,我有一些is_a关系,例如:

is_a(cow, animal).
is_a(calf, cow).
is_a(dog, animal).
.... etc.
我希望有一个执行以下操作的过程:

toAnimal(cow, X).

that outputs
X= [calf, cow, animal].
基本上,如果我给它一个输入(cow),那么它将从cow一直到animal,并将每个步骤添加到列表中

到目前为止,我有:

toAnimal(A, B) :- is_a(A,B).
toAnimal(A, B) :- is_a(A, X), toAnimal(X, B).
其输出为

X= cow;
X = animal;
false
我怎样才能把它变成一个列表

编辑:

在看了这个建议之后,我更新了它。但是,如何打印列表?我对序言还是新手。findall页面说它会返回列表,但不是为我这样做

toAnimal(calf, Y)
outputs:
false.
编辑:

它现在返回一个空列表。我不确定这里有什么问题。我根本没有更改代码,因此输出不应该更改,但它已经更改了

编辑:

谢谢布拉奇先生的回复。 我做了建议的修改,但我现在有另一个问题。 例如 如果我有关系:

is_a(calf, cow).
is_a(calf, animal).
is_a(cow, cool).
is_a(cool, awesome).
但我只想要从小牛到令人敬畏的道路。 代码将给出calf,x的所有可能路径。 比如说,

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).
会给我一份清单吗

[cow,animal,cool,awesome].
但我想要的是

[calf,cow,cool,awesome].
如何过滤其他路径? 还要加起点吗?我想我可以将calf附加到开头作为head,但是如何忽略其他路径呢

编辑:

谢谢你的帮助 我想出来了,但我失去了终点和起点。例如 我有牛,酷。 但是小牛和可怕的不在那里。我试着附加,但我不太懂语法。我不允许做附加(X,L,一个新列表)

toAnimal(X,Y):-setof(X,down('animal',X),Y)。
应该这样做。或
findall/3

但请记住,您要求的是下降(动物,X),因此它与以下事实不匹配:
是一只(狗,动物)
,例如,
下降(动物,X)
将。你需要使
下降
来搜索两边,或者只需确保你的
是一只在左边的动物

如果你想过滤,你可以这样做

toAnimal(X,Y):-setof(X,(下降('animal',X),而不是(X=animal)),Y.


但是你得到的是
动物
,因为我前面提到的。

这个样本或多或少符合你的要求:

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).
运行时,这是输出:

[莱西,柯利牧羊犬,狗,动物][柯利牧羊犬,狗,动物]

使用

后期编辑:啊,就是这样!我应该在第一句写“[X,animal]”而不是“[X | animal]”!非常感谢@mbrach,现在该程序完全实现了预期目的。

在这里。(注意:不需要使用下降谓词来计算树的特定分支的路径)

用法:

| ?- find_path(calf,awesome,L).

   L = [calf,cow,cool,awesome] ? ;

您可以使用
findall/3
setof/3
。请参阅序言文档,了解它们是如何工作的。您没有使用
B
作为列表,而是将其与一个基本术语(即
animal
)统一起来。我对我的帖子进行了编辑,我不确定现在如何打印列表。谢谢你的回复!这类函数的诀窍是添加一个额外的参数,该参数不是原始调用方真正使用的,而是由函数用作存储此类列表的临时位置,在该额外参数中,将每一步放在列表的开头:[X | Y]这不是使用
findall/3
的正确方法。因为您使用的是
findall/3
,所以不应该实例化第一个参数,这就是整点。否则,您只需选择一个特定的
X
。如果找到满足特定标准的
X
的所有值,则
findall
会做什么。像
findall(X,后代(cow,X),L)
将创建一个列表
L
,其中包含使
后代(cow,X)
为true的所有
X
。或者您可以编写
toAnimal(Y):-findall(X,后代(Y,X),L)。
然后查询
toAnimal(cow)。
很抱歉,我忘了在前面指定我想要到指定点的特定路径。但这确实适用于所有路径。我在我的帖子中对此进行了编辑。感谢您的回复,尽管我非常感谢您的帮助。请查看如何使用
减少回溯。谢谢,这非常有帮助<代码>[X |动物]
是一个由一个元素组成的列表,即复合词
|(X,动物)
。在这个上下文中,它没有太多的语义意义。如果你想有一个包含两个元素的列表
X
animal
,你只需要编写它
[X,animal]
。工作完美!!对不起,“\+”是做什么的?如果不是要求太高,请您简单描述一下您的解决方案是如何工作的?@JoePineda
\+
是“无法证明”。哦!谢谢但是在这种情况下,如果你只是把第二个“路径”的定义移到第一个定义之上,那不是一样吗?如果失败,prolog将尝试使用更长的定义,在这种情况下,“\+is_a(X,Y)”的检查将是多余的。我的意思是这样的,尝试过它,至少在这个小示例中工作正常:path(X,Y,[Y]):-is_a(X,Y)。path(X,Y,[Z | T]):-是_a(X,Z),path(Z,Y,T)。让你的子句互斥是件好事,不管它们的顺序如何。对于初学者来说,让谓词的意义依赖于它的从句顺序通常被认为不是一个好的做法。话虽如此,你看。
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).
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).
| ?- find_path(calf,awesome,L).

   L = [calf,cow,cool,awesome] ? ;