我是Prolog的新手,我正在研究它进行普通考试,我们使用SWI Prolog
我有一些问题需要理解,如果列表S是列表L的子列表,这个简单的程序如何说明为TRUE,否则说谓词为FALSE。
我有以下解决方案,但我有一些问题需要理解它的声明性含义
读这本书我认为我有一些想法,但我不确定...
这是使用串联的解决方案:
sublist(S,L) :- conc(L1, L2, L),
conc(S, L3, L2).
conc([],L,L).
conc([X|L1],L2,[X|L3]) :- conc(L1,L2,L3).
如果第三个列表是第一个和第二个列表的串联,此解决方案使用另一个响亮的程序。
如果L的S i子列表必须为TRUE,则表示以下两个条件:
这是书的解释,但对我来说只是一个小小的障碍......
我试图对此进行推理并尝试理解真正深刻的意思......
所以我认为,在某种程度上,它就像使用这个其他程序搜索元素是否是列表的成员一样:
member2(X, [X|_]).
member2(X,[_|T]):- member2(X,T).
在这个程序中,我只是说如果X是列表顶部的元素(它的头部),则X在列表中,程序响应为true。否则,如果X元素不在列表的顶部(或者它不是我的解决方案),我会尝试将其搜索到此列表的TAIL T.
回到子列表程序我认为推理类似
首先我在两个列表L1和L2中分解L列表(使用浓缩程序)**
然后我检查S和L3的串联是否为L2列表是真的。
如果展位这些条件是真的那么S是L的子列表
我认为L1列表与我从成员程序列表中提取的X元素具有相似的作用。
由于子列表S可以从列表L的开头开始,L1可以是[],我可以在L1 = []和L2的串联中分解L,我可以尝试在S中分解L2和L3。
如果我可以做最后一次分解,那么程序结束,我可以说S确实是原始列表的子列表L
如果不是 conc(S,L3,L2),那么ddo回溯并采取另一个计算分支
我的陈述性解释是否正确?
我发现这个例子有很大的困难,我也试图找到程序解释(使用Prolog shell中的操作跟踪),但是我有很大的问题因为计算它对于一个简短的列表来说也是如此之大。
答案 0 :(得分:1)
本书的解释更具说明性,因为它没有调用Prolog的搜索机制。我可能会用更多的下划线写这个:
sublist(S, L) :- append(_, Suffix, L), append(S, _, Suffix).
这至少使S和L2(更名为Suffix)之间的关系更加清晰。我们想要说的是,并且在声明性英语中很难清楚地表达,如果有一个后缀为L的后缀,那么 S是L的子列表,后缀是后缀 。命名其他成分只会增加混乱。 Prolog将在内部命名这些变量,并在尝试统一其他所有内容时与它们统一,但它不会与调用者共享该信息。虽然这些变量在某种意义上需要存在,但它们与你的公式没有密切关系,或者它们不是单身人士。每当得到单例变量警告时,用下划线替换变量。它会增加清晰度。
碰巧由于所涉及的前缀和后缀可以是空列表,S可以是L的正确前缀或L的正确后缀,一切都会成功。
member/2
的声明性读取,供参考,是如果X是列表的头部,或者如果X是列表尾部的成员,则X是列表的成员。请仔细注意缺少的内容:提及检查,成功或失败,或者实际上是任何操作顺序。如果它是尾部的成员或者是头部的话,那么 X是列表的成员同样是声明性的。使计算机执行的只是生活中不可避免的事实。计算它必须以某种顺序完成,所以你必须以正确的顺序告诉Prolog事情,否则它将进入无限循环,但这不是逻辑的一个方面,只是Prolog。
由于我们已经过了好几次,当你调用Prolog的机器时,你不再是一个声明性的阅读。所以,当你说,“首先我分解......”你已经离开了声明世界并进入了程序世界。声明世界没有步骤,即使Prolog必须按特定顺序执行操作以在现实生活中的计算机上执行计算。同样,在声明性阅读中,您不会检查事物,它们只是或不是。单词 backtrack 也不能作为声明性阅读的一部分出现。你应该在陈述性阅读中使用的唯一“动词”是存在的动词,“是”。
那就是说,你的Prolog /程序读物是完全正确的。