2011-03-02 59 views
0

我想通过例子来理解序言。我写了一段代码,但没有按照预期的方式工作,我无法找到故障。用列表操作

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的工作。所以请有人能告诉我我的错在哪里以及在这段代码中需要做些什么修改才能正常工作。

回答

1

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

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

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

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

第二个子句处理递归。它将输入列表的第一个元素添加到中间列表的前面,生成另一个中间列表。 现在您再次执行递归调用测试。但请注意,现在三个参数被实例化了!所以你将无法将其他项目追加到最终列表中。

这里去您的测试/ 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). 
+0

中的代码,非常感谢您提供了这样一个描述性答案。它有很多帮助。 :) – anilonwebs 2011-03-02 14:07:42

0

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

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

具有test一个隐含的附加操作将使得递归更容易编写。此外,请注意,您可以将append([A], B, C)编写为C = [A | B](或者用[A | B]替换C)。

+0

谢谢你的建议,但我想用递归也。我对结果不感兴趣,但它应该正常工作我想知道其故障运行背后的原因。我试图修改我的代码,但它也不起作用。我已经更新了问题部分 – anilonwebs 2011-03-02 10:08:25