我正在阅读这个问题的答案,
p(X) :- read(A), q(A,X-[]).
q(end,X-X) :- !.
q(A,[A|X]-Y) :- read(B), q(B,X-Y).
上面的代码使用语法List-List。我有点理解发生了什么,但我想知道“-”符号/谓词在这里究竟做了什么。另外,这个 SWI 是特定的吗?
我正在阅读这个问题的答案,
p(X) :- read(A), q(A,X-[]).
q(end,X-X) :- !.
q(A,[A|X]-Y) :- read(B), q(B,X-Y).
上面的代码使用语法List-List。我有点理解发生了什么,但我想知道“-”符号/谓词在这里究竟做了什么。另外,这个 SWI 是特定的吗?
(-)/2
表示差异列表是一个相当不常见的约定。在较旧的书中,(\)/2
也使用了另一个运算符。
许多人更喜欢使用两个单独的参数。与使用运算符相比,有几个优点:
谓词不能意外地与参数的未实例化变量一起使用。考虑调用q(A, X)
代替q(A, X-[])
.
使用两个参数时,执行效率甚至更高。许多系统,如 SWI,必须(-)/2
动态创建每个结构。
不过,还有另一种使用差异列表的方法,这种方法通常不太容易出错:您可以为此目的使用dcg 。
实际上,程序有两个错误,其中一个是差异列表的处理方式造成的。另一个错误是程序不处理文件结尾。end_of_file
代替.使用会更好end
。但这是一件肤浅的事情,你迟早会发现自己。
另一个更细微的错误是由于差异列表和剪辑之间的相互作用造成的。我不是削减的忠实粉丝,但让我们看看这条规则。在其左侧的所有内容都已执行后进行剪切。
q(end_of_file,X-X) :- !.
第一个参数是 atom end_of_file
。由于我们q/2
只使用作为第一个参数的结果read/1
,这只能是一个比较。所以我们在文件(或流)的末尾。然而,还有更多的事情必须坚持。只有当它们也成功时,才会执行剪切:第二个参数必须是 a (-)/2
(好吧,在所有地方都有一个减号)。然后: 的两个参数(-)/2
必须相同(必须统一)。为什么?我们在文件的末尾,但如果这些参数不统一,将尝试另一个规则。
这什么时候发生?这是一个令人讨厌的案例:
p([X,Y,Z]).
只需输入一个常数,比如说my_constant.
然后按Cntrl-d或Cntrl+z。p/1
在这种情况下应该怎么办?理想情况下,它会在您完成输入后失败。但是,它将等待进一步的输入。
原因是切口放置不当。p/1
我们说不坚定。这是 Prolog 程序中的常见错误。我只能建议减少削减的使用和 DCG 的采用。使用 DCG,这不会发生:
p2(X) :- read(A), phrase(q2(A),X).
q2(end_of_file) --> !.
q2(A) --> [A], {read(B)}, q2(B).
对于 DCG,无论 的参数如何,都会执行剪切p/1
。