打印列表元素-两种解决方案有何不同?

时间:2018-10-02 04:49:41

标签: prolog

我目前正在经历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).

还有许多其他练习以类似的方式解决;尽管我可以追踪这些解决方案并验证其正确性,但我还是对这种方法感到困惑。因此,请您指出以上解决方案之间的区别?我发现我的逻辑性和直截了当的多了,我还不太了解第二个!

1 个答案:

答案 0 :(得分:1)

如果我必须在两种解决方案之间进行选择,那么实际上我比第一种教科书更喜欢第一种解决方案。至少我看不到第二种方法的优势,这两种解决方案都是Prolog的当务之急。如果列表足够大,则可以进行性能比较,如果那是重要因素。两者都有一个有点尴尬的调用约定,即使您根本不在乎它是什么,也需要提供第二个参数。第二种解决方案具有两个任意命名的谓词printAprintB,它们之间似乎没有足够可区分的语义。您可以调用printA(MyList, 0).printB(MyList, 0).并获得(某种)相同的结果(其中一个具有一个额外的缩进级别)。

printA/2print/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。