如何在Prolog中返回一个列表?

5

假设我有以下这些事实:

parent(bob, sam). %bob is sam's parent
parent(sara, sam). %sara is sam's parent

我想找出谁是萨姆的父母,并以列表形式返回他们,因此使用了以下代码:
list_parents(P, L) :- findall(Parent, parent(Parent, P), L).

我现在想做的是用一个参数来问同样的问题,如下所示:

findParents(sam).

我已经尝试过:
findParents(Name) :- list_parents(Name, L).

但是这种方式Prolog只会简单地回答"True"


2
不可能的。别这么做。Prolog除了布尔值之外没有返回值。 - Fred Foo
3个回答

8

Prolog与大多数语言有所不同(如果说这是一种轻描淡写的话):

  • 所有变量都是局部作用域的。

  • 一旦绑定(统一),变量值就是不变的,除非回溯取消绑定。

  • 谓词不以传统意义上的返回值形式返回值。它们要么成功,要么失败。

  • 为了从测试谓词中获取值,您需要评估谓词,并将某些东西从您的谓词传递给它。无论您传递变量还是已绑定的值,都没有关系:被调用的谓词将会成功或者失败,如果调用者统一了您传递给它的内容,那么它就会返回值。如果您传递了一个变量,并且被调用的谓词将其统一为非变量值,则您的变量将绑定到该值。可以将其视为(在某种程度上)具有过程语言的功能,其中每个函数都返回bool,所有参数值都通过引用传递。

你尝试的方法是有效的:

findParents(Name) :- list_parents(Name, L).

变量L与findall/3返回的列表统一了(绑定在一起)。然后,它就超出了范围。如果您希望实际上使用返回的(绑定的)值,您需要在其范围内处理它,或将该值与调用该谓词的某些东西统一,从而将其传递到调用堆栈上。或者,您可以将其断言到事实数据库中,并将其保存供以后使用。Prolog的工作方式是,用于启动“程序”的根谓词根据数据库中的谓词定义搜索树。然后,Prolog的“引擎”按深度优先、从左到右的顺序搜索该树。当引擎到达您定义的搜索树的叶节点时,您的谓词成功。回溯到您的谓词会导致引擎在搜索树中查找下一个解决方案。因此,您想要以持久方式实现的任何事情都必须作为Prolog“引擎”评估谓词的副作用发生。例如,print()总是成功一次(当您输入框时)……并作为打印所请求的内容的副作用。回溯到打印不会“取消”打印,但print()不会再次成功。

3

func库提供了在SWI-Prolog中具有返回值的函数的语法。在此示例中,您可以通过编写writeln(list_parents $ sam)来打印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).

2
如果你只想让用户看到列表,可以打印它,例如:
findParents(Name):-
   list_parents(Name,L),
   print(L).

但这并不完全是返回值。请记住,在Prolog中,没有函数,因此也没有“返回值”。您可以通过编写foo(Args,Return)来模拟函数,但是您始终可以像foo(X,sam)一样调用它-有时它会给出您想要的结果,有时不会,有时会崩溃。


这是我的问题。我以前用过很多编程语言,但我就是无法理解这个应该如何工作。虽然我不需要打印出来,但我需要与调用list_parents“函数”得到的结果相同。 - porlognewbie
好的,只需使用变量调用谓词list_parents,并将其存储在你想要的位置。例如:list_parents(sam,List)。然后Prolog将把List与sam父母的列表统一起来。如果这样更容易理解,你可以想象它相当于List=list_parents(sam),但这并不完全正确。 - Thanos Tintinidis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接