2017-01-11 28 views
1

当我写下this question on an empty list as a difference list我想考什么,我知道那些结构。但是,当我尝试一些比较不同符号的简单事情时,似乎我错了,并且我确实知道实际上差异列表正在发生什么。如何使用差异表的Prolog的解释

?- L = [a,b,c|[d,e]]-[d,e], L = [a,b,c]. 
false % expected true 

我在SWI-Prolog和SICStus上测试了这个。我验证了这个符号,因为它是如何写在Bratko的人工智能Prolog编程中,第210页,但显然统一是不可能的。这是为什么?这些符号不具有相同的声明意义吗?

+2

阅读该部分的关键是*代表*。如果你看一下这本书,那么当这些例子可以与最高级别的AKA解释器一起使用时,它们的前缀是“?-'。例如,[a,b,c] - []或[a,b,c,d,e] - [d, e]或[a,b,c,d,e | T] - [d,e | T]或[a,b,c | T] -T其中T是任何列表。'所以它不是一个例子以最高级别运行,但代表*表示*您应该考虑的内容,因此在将其用作顶级输入时出现错误。 –

+1

'L'不能都是'[a,b,c | [d,e]] - [d,e]'和'[a,b,c]'。这是两种不同的结构。 – lurker

+0

@lurker我现在看到了,但正如在评论中澄清的那样,可能是为什么我没有看到差异列表的实际好处。如果你想使用连接列表,你总是需要Willem Van Onsem建议的* finalize *步骤。 –

回答

3

我认为你有这样的想法,Prolog解释器将差异列表视为特殊的东西。情况并非如此:Prolog没有意识到差异列表的概念(几乎除了某些语法糖之外的几乎所有概念)。他只看到:

L=-(|(a, |(b, |(c, |(d, |(e, []))))), |(d, |(e, []))) 

其中-/2|/2是仿函数,并abcde[]是常数。

差异列表是一个简单的编程技术(例如像动态规划是一种技术,以及时,编译器无法检测,也不区别对待动态编程程序)。它用于高效地将表达式中的(部分)非统一部分统一起来。

说要append/3两个列表。你可以这样做如下:

%append(A,B,C). 
append([],L,L). 
append([H|T],L,[H|B]) :- 
    append(T,L,B). 

但这运行在O(n)的:您首先需要通过整个第一个列表进行迭代。如果该列表包含数千个元素,则需要很长时间。

现在,您可以定义自己合同,你会养活append_diff/3不仅列表中,但一个元组-(List,Tail)其中List是到列表的开始时的参考,并Tail是的末尾引用没有统一的名单。符合此要求的结构示例为Tail-Tail,[a|Tail]-Tail,[1,4,2,5|Tail]-Tail

现在可以有效append_diff/3O(1)有:

append_diff(H1-T1,T1-T2,H1-T2). 

为什么?因为你统一第一个列表的非统一的尾巴与第二个列表。现在第二个列表的非统一尾部成为最终列表的尾部。因此,采取例如:

append_diff([a|T1]-T1,[1,4,2,5|T2]-T2,L). 

如果调用谓词,正如你看到的上面,T1将与[1,4,2,5|T2]统一,所以现在第一个列表折叠到[a|[1,4,2,5|T2]]或更短[a,1,4,2,5|T2],因为我们也有一个参考T2,我们可以“返回”(在Prolog中没有任何内容是返回),[a,1,4,2,5|T2]-T2:带有开尾的新差异列表T2。但是,这仅仅是因为你给-特殊的含义自己:为序言-简直是-,它不是减去,它不计算差值等Prolog的不不重视语义函子。如果你会使用+而不是-,那就不会有丝毫的区别。

所以要回到你的问题:你只需向Prolog说明L = -([a,b,c,d,e],[d,e])和后来的状态即L = [a,b,c]。现在很明显,这两种表达方式是不能统一的。所以Prolog说false

+0

我现在明白他们为什么不统一,但我不明白append_diff/3在实践中会很有用。我的意思是,如果这就是你如何添加,结果将是'[a,1,4,2,5 | T2] -T2'。你仍然没有你想要的价值,即'[a,1,4,2,5]',对吧? –

+0

@BramVanroy:好吧,你可以定义一个谓词'finalize(A - [],A)。“,它可以”完成“diff列表。如果你接着调用'finalize([a,1,4,2,5 | T2] -T2,Result)。''Result'将会是'[a,1,4,2,5]'。但正如前面所说,你自己如何解释数据是一回事。你可以将'[a,1,4,2,5 | T2] -T2'解释为与[[a,1,4,2,5]'相当的列表*等价*。 –

+0

但是Prolog并没有像这样解释结构,所以'finalize/2'步骤需要有一个可用的连接列表,对吗? (关于其他问题发布的评论如下)作为示例,我们要追加[a,b]和[c,d]。建议的解决方案:'conc_d([a,b | T] -T,[d,e | T1] -T1,L).'但是,结果是'L = [a,b,c,d | T1] -T1',但作为程序员,我需要'[a,b,c,d]',简单明了。我有一种感觉我错过了这一观点,但我没有看到实际的好处,也没有看到如何在实践中使用差异列表。 –