我目前正在经历Clocksin&Mellish的“ Prolog中的编程”。其中一个练习要求在缩进嵌套元素的同时在一行上打印列表元素,因此例如,我们需要将[a,b,[c,d],e,f]打印为:
a
b
c
d
e
f
因此,这是我的解决方案(假设我们有一个谓词'indent',它打印指定数量的缩进空格)。我定义了两个谓词“ print”和“ printelement”,每个谓词都带有要打印的第一个参数,第二个用于缩进(空格数):
print([],_).
print([H|T],Indent):- H\=[_|_], % if not a list
printelement(H,Indent),
print(T,Indent).
print([H|T],Indent):- H=[_|_], NewIndent is Indent+2, % if a list, increase the indent
print(H,NewIndent), % NewIndent
print(T,Indent). % Indent
printelement(X,I):- indent(I), write(X), nl. % print individual elements
...,它完成了工作。另一方面,这本书提出了一种解决方案,它也可以完成任务,但是在两个谓词之间来回移动如下:
printA([H|T], I) :- !, J is I + 2, printA(H, J), printB(T, J), nl.
printA(X, I) :- indent(I), write(X), nl.
printB([],_).
printB([H|T], I) :- printA(H, I), printB(T, I).
还有许多其他练习以类似的方式解决;尽管我可以追踪这些解决方案并验证其正确性,但我还是对这种方法感到困惑。因此,请您指出以上解决方案之间的区别?我发现我的逻辑性和直截了当的多了,我还不太了解第二个!
答案 0 :(得分:1)
如果我必须在两种解决方案之间进行选择,那么实际上我比第一种教科书更喜欢第一种解决方案。至少我看不到第二种方法的优势,这两种解决方案都是Prolog的当务之急。如果列表足够大,则可以进行性能比较,如果那是重要因素。两者都有一个有点尴尬的调用约定,即使您根本不在乎它是什么,也需要提供第二个参数。第二种解决方案具有两个任意命名的谓词printA
和printB
,它们之间似乎没有足够可区分的语义。您可以调用printA(MyList, 0).
或printB(MyList, 0).
并获得(某种)相同的结果(其中一个具有一个额外的缩进级别)。
printA/2
和print/2
都将[]
视为一个原子而不是一个空列表。因此:
| ?- print([a,b,[],c], 0).
a
b
[]
c
对于printA([a,b,[],c], 0).
如果我正在写这篇文章,那么我将完全采用另一种方法。首先,我可能要编写一个带有3个参数的谓词:element_depth(List, X, D)
,如果X
在深度为List
的多级列表D
中时成功,否则失败。>
element_depth(List, X, Depth) :-
element_depth(List, X, 0, Depth). % Starts with depth 0
element_depth([X|_], X, Depth, Depth) :-
\+ is_list(X).
element_depth([L|_], X, D, Depth) :-
is_list(L),
D1 #= D + 1,
element_depth(L, X, D1, Depth).
element_depth([_|Xs], X, D, Depth) :-
element_depth(Xs, X, D, Depth).
现在您有一个Prolog谓词,其行为更像一个谓词,而更不像C函数。您使用它进行查询并提供解决方案。您可以执行以下查询:
| ?- element_depth([a,b,[d, []], c], X, D).
D = 0
X = a ? a
D = 0
X = b
D = 1
X = d
D = 0
X = c
no
| ?- element_depth([a,b,[d,[]], c], X, 1).
X = d ? ;
no
| ?- element_depth([a,b,[d,[]], c], c, D).
D = 0 ? ;
no
如果要对结果进行格式化打印,可以编写一个特定的格式化谓词来调用它:
print_elements(L) :-
element_depth(L, X, D),
N #= D * 2,
indent(N),
write(X), nl,
fail.
然后您可以这样拨打电话:
| ?- print_elements([a,b,[d,[]], c]).
a
b
d
c
no
| ?-
这看起来像一些代码,但是更通用,更Prology。