对于像我这样的Prolog初学者来说空列表是......很奇怪。我会说,将空列表[]
写为差异列表T1-T2
是不可能的,因为不可能将原子写为差异列表。但是,我猜想要使用递归,必须有一种方法可以在差异列表设置中使用[]
。我有谷歌这个,但我找不到答案,而Bratko(人工智能的Prolog编程)只是简单地触及了这个主题。
那么,是否有可能在Prolog中将空列表作为差异列表编写,如果可以,它将如何以及何时有用?
答案 0 :(得分:5)
理解此主题的问题通常是由于使用误导性术语。
根据tutorial.pdf中的建议,尤其是pap95.pdf,例如使用列表差异或只是差异。
Teaching beginners Prolog的第5部分包含相关原因。
空列表由原子 []
唯一表示。
请注意,列表差异总是意味着对两个列表的推理,并且由于单个列表和多个列表之间的这种明显区别,您最多可以找到一些对应关系或类比,但 not空列表与列表差异之间的身份。
我完全支持上述论文中表达的观点,你应该专注于使用DCG ,至少在开始时。明确地对差异进行推理将在以后自然而然地发生。
答案 1 :(得分:0)
附加两个列表差异意味着只有第一个差异的结束指针与第二个头部的统一。使用常规列表,它需要回溯第一个列表的整个列表结构。因此,右侧的重复串联是线性与列表差异技术,二次与普通列表。
当完成所有预期的连接时,要将整个结构作为普通列表返回给调用者,我们只需统一"结束指针" logvar与[]
。
在C语言中,列表差异是单链表的一部分,其中我们维护两个变量:它的头指针以及它的尾指针:
// typedef struct { int payload; node* next } node;
typedef struct { node** head; node** tail } list_diff;
现在每个连接只是结束指针的赋值:
void diff_concat( list_diff* a, list_diff* b)
{
*(a -> tail) -> next = *(b -> head);
a -> tail = b -> tail;
}
最终确定
void diff_finalize( list_diff* a)
{
*(a -> tail) = NULL; // or some sentinel value, whatever
}
在Prolog中,我们可以将其表示为-/2
之类的二进制术语,例如-(A,B)
或A-B
。
但是(在C中也是如此)没有实际需要在内存中构建实际结构只是为了保持两个指针;我们可以单独维护两个logvar。或者让DCG为我们做。
以上是列表差异技术的动机介绍,"它们有什么用?"。它还清楚地表明空差的表示是
list_diff* d;
*(d -> head) = *(d -> tail);
或者在Prolog中,一对彼此统一的日志:L-L, var(L)
。要了解原因,请查看当空差异在其右侧附加了一些其他差异时会发生什么(始终在右侧我们追加事物,从而增加自上而下的列表方式)。我的C可能在这里,这个想法是通过设置尾部附加到空的差异也会更新它的头部。