让我说我有这些事实:
parent(bob, sam). %bob is sam's parent
parent(sara, sam). %sara is sam's parent
我想知道谁是 sam 的父母,并将其归还给一个列表并使用:
list_parents(P, L) :- findall(Parent, parent(Parent, P), L).
我现在要做的是问同样的问题,但只有一个论点:
findParents(sam).
我试过了:
findParents(Name) :- list_parents(Name, L).
但这样Prolog只回答"True"
。
答案 0 :(得分:8)
与prolog相关的是它与大多数语言略有不同(轻描淡写,如果每一种语言都是如此):
所有变量都是本地范围的。
变量值在绑定(统一)后是不变的,除非回溯取消绑定。
谓词不会返回传统意义上的值。他们要么成功要么失败。
要从测试谓词中获取值,您可以评估谓词从谓词中传递一些内容。如果你传递一个变量或一个绑定值并不重要:如果调用者已经与你传递的内容统一了,那么被调用的谓词将成功或值。如果传递了一个变量,并且被调用的谓词将其与非变量值结合,则您的变量将绑定到该值。想想(有点),好像你有一个过程语言,其中每个函数返回bool并且所有参数值都通过引用传递。
您尝试过的工作:
findParents(Name) :- list_parents(Name, L).
变量L与findall/3
返回的列表统一(已绑定)。然后它超出了范围。
如果你想用返回的(绑定的)值实际做某些东西,你需要在它的范围内处理它,或者将该值与该谓词被调用的东西统一起来。从而将其传递给调用堆栈。或者,您可以将其断言到事实数据库中并保存以供日后使用。
prolog的工作方式是用于启动“程序”的根谓词根据数据库中的谓词定义搜索树。 Prolog的“引擎”然后执行该树的深度优先,从左到右的搜索。当引擎到达您定义的搜索树的叶节点时,您的谓词会成功。回溯到谓词会导致引擎在搜索树中查找下一个解决方案。
因此,您希望以持久方式完成的任何事情都必须作为评估谓词的prolog“引擎”的副作用。例如print()
总是只成功一次(当你进入盒子时)...并且副作用会打印你要求它打印的任何内容。回溯到打印中不会“撤消”打印,但print()
不会再次成功。
答案 1 :(得分:2)
如果只想让用户看到它,你可以打印列表 类似的东西:
findParents(Name):-
list_parents(Name,L),
print(L).
但这并没有完全恢复。记住,在prolog中,没有函数,因此没有“返回值”。你可以通过编写foo(Args,Return)来模拟一个函数,但你可以像foo(X,sam)一样调用它 - 有时候它会给你想要的东西,有时它会不会,有时它会崩溃。
答案 2 :(得分:2)
func库为SWI-Prolog中返回值的函数提供了语法。在此示例中,您可以通过编写sam
:
writeln(list_parents $ sam)
的所有父母
:- initialization(main).
:- use_module(library(func)).
main :- writeln(list_parents $ sam).
list_parents(P, L) :- findall(Parent, parent(Parent, P), L).
parent(bob, sam). %bob is sam's parent
parent(sara, sam). %sara is sam's parent
同样,您可以定义一个具有多个参数的函数,例如:
% return a item at an index in a list.
nth0((Index,List),ToReturn) :-
nth0(Index,List,ToReturn).
...然后像这样使用它:
example :-
ListIndex = (nth0 $(0,[1,2,3,4])), %returns 1, which is the first item in this list
writeln(ListIndex).