操纵列表

时间:2011-03-02 09:22:56

标签: prolog

我试图通过例子来理解序言。我写了一段代码,但它没有以理想的方式工作,我无法找到错误。

list([]).


test([],_,_).                   
test([Child|List],B,C) :-
   append([Child],B,C),
   test(List,B,C).  

testme :-
        list(Final),
        test([1,2,3],Final,Result),
        write(Result).  

我需要从此代码中Result应该与输入列表相反的功能。当我跟踪这段代码时,我在C中找到了输入列表的反向,但是没有返回。

我知道使用reverse函数我可以很容易地找到列表的反向但我的兴趣不是找到反向,而是要理解这段代码和prolog的工作。所以,有人可以告诉我我错在哪里以及在此代码中需要进行哪些修改才能正常工作。

2 个答案:

答案 0 :(得分:1)

首先让我们看看为什么你的代码不起作用。

test([],_,_).                   
test([Child|List],B,C) :-
   append([Child],B,C),
   test(List,B,C). 

您尝试使用两个子句定义递归谓词。 这个谓词的参数是:输入列表(1),中间列表(2)和最终结果(3)。

你的第一个条款是错误的。 假设您的输入列表只是一个空列表。结果应该是一个空列表。但是在你的第一个条款中,你将按原样离开第三个参数。要么它已经被束缚(在这种情况下没有用),要么它是无界的,因此它会保持这种状态。

第二个句子涉及递归。它接受输入列表的第一个元素,将其附加在中间列表的前面,产生另一个中间列表。 现在,您再次执行递归步骤调用test。但请注意,现在三个参数都被实例化了!因此您将无法将其他项目附加到最终列表中。

这里修改了test / 3谓词,使其按预期工作:

test([],List,List).
test([Child|List],B,D) :-
   append([Child],B,C),
   test(List,C,D). 

现在第一个子句统一了第二个和第三个参数。 所以在我们的第一个测试用例(空输入列表)中,回想一下第二个参数也是一个空列表,所以第三个参数也是一个空列表=>正确的。

现在为递归子句。 它将获取输入列表的第一个元素并将其附加到中间列表,并将其统一到一个新变量上。 现在我们进入递归步骤,但现在我们使用该列表(C)作为中间列表。 在递归时,这将构建输出列表,现在绑定到D,这是我们用作输出的。

由于您每次只向中间列表添加一个元素,您可以删除附加内容,例如:

test([],List,List).
test([Child|List],B,C) :-
   test(List,[Child|B],C).

答案 1 :(得分:0)

Prolog规则只能通过将它们与参数统一来“返回”值(因为参数和返回值之间没有区别)。假设您需要基于累加器的reverse操作,则需要三个参数test,并且它应该像写为:

test(A, B, C) :- reverse(A, A2), append(A2, B, C).

test中进行隐式追加操作将使递归更容易编写。另请注意,您可以将append([A], B, C)写为C = [A | B](或将C替换为[A | B])。