Prolog - 打印带有 format/2 的列表列表

Prolog - Print list of lists with format/2

这是我使用的代码:

printElement(L/C) :- format('~t~a - ~a~t~20+|', [L, C]).
printElement(L) :- format('~t~a~t~20+|~t', L).

printList([]) :- format('~n', []).

printList([H|T]) :-
    printElement(H),
    printList(T).

printLists([], _).
printLists([H|T], N) :-
    M is N + 1,
    format('~d- |', M),
    printList(H),
    printLists(T, M).

作为 BL 列表的列表我将谓词称为 printLists(BL, 0).

我的目标是将 BL 显示为 9x9 网格,单元格大小相同。 相反,我得到了这个:

我希望所有列都显示为图像中的第一列,我的意思是我希望所有其他单元格具有相同的宽度。

为什么我的代码不适用于第二列等等?

此机制的问题在于,在这种情况下,出于某种原因,format/2 列定位在多次调用 format/2 之间似乎无法按预期工作。但是,如果您使用 ~@ 格式说明符,它实际上会起作用 [好吧,它 可能 起作用,因为我只能在 SWI Prolog 上尝试它具有相同的format/2 个选项]。

~@ 格式选项告诉 format 调用下一个参数作为 Prolog 谓词。

这是一个例子。而不是这个:

printElement(L/C) :- format('~t~a - ~a~t~20+|', [L, C]).
printElement(L) :- format('~t~a~t~20+|~t', L).

试试这个:

printElement(L) :-
    (   L = A/B
    ->  format('~@', print2(A, B))
    ;   format('~@', print1(L))
    ).

print2(L, C) :- format('~t~a - ~a~t~20+|', [L, C]).
print1(L) :- format('~t~a~t~20+|', L).   % Not sure why you have the extra '~t'
                                         %  in your format; I removed it

请注意,我放入 if-else 结构是为了避免第二个 printElement/1 匹配 L/C 形式。

这是一种不同的方法,它使用构建格式字符串(实际上是一个原子)的谓词和基于输入行的更新数据列表。这通过为整行构建单一格式字符串来规避每行多种格式的问题,以便可以为每一行调用单个 format/2

% makeFormat/4
% makeFormat(-RowData, -FormatPrefix, +NewRowData, +Format)
%
makeFormat([], F0, [], F) :-
    atom_concat(F0, '~n', F).
makeFormat([E|Es], F0, L, F) :-
    (   E = A/B
    ->  atom_concat(F0, '~t~a - ~a~t~20+|', F1),
        L = [A,B|Ls]
    ;   atom_concat(F0, '~t~a~t~20+|', F1),
        L = [E|Ls]
    ),
    makeFormat(Es, F1, Ls, F).

printLists([], _).
printLists([H|T], N) :-
    M is N + 1,
    makeFormat(H,'~d- |',  H1, Format),  % make format starting with '~d- |'
    format(Format, [M|H1]),              % write out the list with prefix
    printLists(T, M).

这是在 SWI Prolog 中有效的另一种方法。您需要在 SICSTUS Prolog 中尝试它,看看它是否也能在那里工作。只需对您的原始解决方案进行以下谓词更新:

printElement(L/C) :- format('~0+~t~a - ~a~t~20+|', [L, C]).  % added '~0+'
printElement(L) :- format('~0+~t~a~t~20+|', L).              % added '~0+'

printList([]) :- format('~n').   % [] argument unnecessary in format, so removed

printElement 中,我在每个格式字符串(原子)的开头添加了一个 ~0+ 以在其余格式发生之前建立相对列位置。如果这在 SICSTUS 下不起作用,您可以尝试 ~1+。但是在 SWI 中,我使用 ~0+ 获得了预期的输出。我更喜欢这个解决方案,而不是将任意长的格式字符串粘贴在一起。

原码测试:

?- printList([a,b,c]).
         a          |b|c|
true.

更新代码测试:

?- printList([a,b,c]).
         a          |         b          |         c          |
true.