结构(差异列表)Prolog

use*_*302 5 prolog dcg difference-lists

这个问题涉及书中第3章的内容:Prolog,Clocksin和Mellish编程,Ed 5

在本书的第72页中,显示了使用差异列表的程序:

partsOf(X,P):- partsacc(X,P,Hole) , Hole=[].

partsacc(X,[X|Hole],Hole):-basicpart(X).
partsacc(X,P,Hole):- assembly(X,Subparts), partsacclist(Subparts, P, Hole).

partsacclist([],Hole,Hole).
partsacclist([P|T], Total, Hole):- partsacc(P,Total,Hole1), partsacclist(T,Hole1,Hole).
Run Code Online (Sandbox Code Playgroud)

在许多在线教程中,使用了以下使用" - "的格式,例如::

append([ A , B , C | R1 ] – R1 , [ D , E | R2 ] – R2 , R3)
Run Code Online (Sandbox Code Playgroud)

我的问题是:

  1. 这两个表示之间有什么区别(使用 - 而不是使用它)

  2. 在哪些情况下最好使用它们中的每一种?

谢谢

fal*_*lse 7

通过各种手段:不要使用(-)/2(\)/2任何其他运算符来表示"差异列表".原因是您经常会有一个带有一个列表参数的谓词和一个使用差异列表的内部谓词.由于两者具有相同的特征,可能也有相同的名称,所以事情会变得混乱.更糟糕的是,它可能适用于"某些情况".此外,该运算符将产生一些成本,您可以通过两个单独的参数来避免.

尽量坚持一个干净的命名约定.也就是说S0,S1...... S.以这种方式,表示差异列表的参数将很容易看到.为了更好地强调这些参数属于一起,有些人在分隔逗号后不使用空格,而是将它用于其他参数.从而:

p(L+R, S0,S) :-
   p(L, S0,S1),
   p(R, S1,S).
Run Code Online (Sandbox Code Playgroud)

此外,(-)/2Prolog还有另一个含义.它用于表示一对Key-Value,如keysort/2.

我所知道的任何Prolog书都暗示了差异列表的运算符来自20世纪80年代.


小智 6

我在Prolog中的经验是有限的,但似乎较旧的文本倾向于使用该-字符或其他字符(例如\)来表示列表及其尾部.较新的Prolog代码总是使用两个参数(如第一个示例中所示).例如,SWI-Prolog中的所有内置和库谓词始终使用两个单独的参数.

理论上,你喜欢哪种风格没有区别.我想在你自己的代码中保持一致并没有什么坏处.

在实践中,不同之处在于,不是在一个参数中包含两个列表的复合术语,而是有两个参数,这应该是更有效的表示.

编辑

确保也阅读@false的答案.


mat*_*mat 6

我同意鲍里斯(+1)关于不同表述的内容.此外,在我看来,这显然是一种情况,你应该使用DCG而不是明确地编码列表差异.例如,考虑以下版本的代码:

parts(X) --> { basicpart(X) }, [X].
parts(X) --> { assembly(X, Parts) }, assembly_(Parts).

assembly_([])     --> [].
assembly_([X|Xs]) --> parts(X), assembly_(Xs).
Run Code Online (Sandbox Code Playgroud)

用法,定义后,assembly/2basicpart/1您的示例完全相同:

?- phrase(parts(X), Ls).

DCG具有清晰的声明性和易于阅读的解释,并且需要较少的参数.