与Prolog的模式匹配问题

时间:2011-04-12 05:04:29

标签: prolog pattern-matching backtracking

编辑:请参阅下面的答案,了解我为什么是个傻瓜。在这方面仍有一个谜,我很乐意回答。

我长期坚持这一点。我正试图在漂亮的网格中打印出一个数独的解决方案。

我认为我遇到了问题,因为我不了解Prolog中模式匹配的一些关键部分。

不用多说,我的代码:

prettier_print([]).
prettier_print([Puzzle]) :- prettier_print(0, [Puzzle]).

prettier_print(0, Puzzle) :- 
    writeln('┌───────┬───────┬───────┐'), 
    prettier_print(1, Puzzle).
prettier_print(4, Puzzle) :- 
    writeln('│───────┼───────┼───────│'), 
    prettier_print(5, Puzzle).
prettier_print(8, Puzzle) :- 
    writeln('│───────┼───────┼───────│'), 
    prettier_print(9, Puzzle).
prettier_print(12, []) :- 
    writeln('└───────┴───────┴───────┘').

prettier_print(N, [Col1, Col2, Col3, Col4, Col5, Col6, Col7, Col8, Col9 | Puzzle]) :- 
    member(N, [1,2,3,5,6,7,9,10,11]),  % tried this when the line below did not work
    % N =\= 0, N =\= 4, N =\= 8, N =\= 13,

    format('│ ~d ~d ~d │ ~d ~d ~d │ ~d ~d ~d │~n', [Col1, Col2, Col3, Col4, Col5, Col6, Col7, Col8, Col9]), 
    succ(N, N1),
    prettier_print(N1, Puzzle).

这是电话:

prettier_print(0, [1,2,3,4,5,6,7,8,9, 
                   2,2,3,4,5,6,7,8,9, 
                   3,2,3,4,5,6,7,8,9, 
                   4,2,3,4,5,6,7,8,9, 
                   5,2,3,4,5,6,7,8,9, 
                   6,2,3,4,5,6,7,8,9,
                   7,2,3,4,5,6,7,8,9,
                   8,2,3,4,5,6,7,8,9,
                   9,2,3,4,5,6,7,8,9]).

这是输出:

┌───────┬───────┬───────┐
│ 1 2 3 │ 4 5 6 │ 7 8 9 │
│ 2 2 3 │ 4 5 6 │ 7 8 9 │
│ 3 2 3 │ 4 5 6 │ 7 8 9 │
│───────┼───────┼───────│
│ 4 2 3 │ 4 5 6 │ 7 8 9 │
│ 5 2 3 │ 4 5 6 │ 7 8 9 │
│ 6 2 3 │ 4 5 6 │ 7 8 9 │
│───────┼───────┼───────│
│ 7 2 3 │ 4 5 6 │ 7 8 9 │
│ 8 2 3 │ 4 5 6 │ 7 8 9 │
│ 9 2 3 │ 4 5 6 │ 7 8 9 │
└───────┴───────┴───────┘
true ;
false.

问题是它不能返回true,我必须按;,然后返回false。这反过来意味着我的prettier_print/1规则无法正常运行。

我想我知道这足以说明这意味着:

Prolog正在回溯并尝试对我的规则进行另一种解释(如果我正确理解我的术语,看看是否还有其他任何可以统一的内容)。这找到了另一件事与它统一,但是立即失败了。是对的吗?

我希望只有一种可能的解释。如何修复我的功能呢?

感谢您的帮助,这让我感觉像个傻瓜!

4 个答案:

答案 0 :(得分:4)

有一种方法可以看到这个,请尝试SWI-Prolog的图形跟踪器:

?- gtrace, your_goal.

跟踪器将显示创建选择点的位置,引入非确定性。在回溯时(例如,当您在顶层按SPACE或“;”时),将考虑剩余的替代条款。

答案 1 :(得分:3)

它正在“返回”true,然后false,因为您正在强制它使用;回溯。由于只有一个解决方案,回溯失败。

此行为仅发生在交互式Prolog解释器中;你要编译程序或在非交互式解释器中运行它,它只会打印结果而不是“返回”任何东西。这有点类似于例如Python解释器

的行为
>>> 'foo'
'foo'

回显输入的最后一个表达式的值,但仅在交互模式下。除非您输入print语句,否则脚本不会打印任何内容。

如果您不想看到false消息,则要么不回溯,即按Enter键而不是;,要么使用metapredicate once/1

?- member(X,[1,2,3]).
X = 1 ;
X = 2 .    % ENTER pressed here

?- once(member(X,[1,2,3])).
X = 1.

?- 

但不要只是在程序中的任何地方这样做,因为它会改变程序的语义。

答案 2 :(得分:2)

回溯时返回true然后返回false的原因是你在条款中留下了选择点。你的应用程序流程只执行prettier_print / 2的一个子句,但prolog解释器事先不知道,所以它留下了一个选择点,然后,在回溯时,将试图查看prettier_print / 2的任何剩余子句是否会成功。

你可以“剪切”回溯,通过使用剪切(!)来承诺一个选择:

prettier_print([]).
prettier_print([Puzzle]) :- prettier_print(0, [Puzzle]).

prettier_print(0, Puzzle) :-
    writeln('┌───────┬───────┬───────┐'),
    !,
    prettier_print(1, Puzzle).
prettier_print(4, Puzzle) :-
    writeln('│───────┼───────┼───────│'),
    !,
    prettier_print(5, Puzzle).
prettier_print(8, Puzzle) :-
    writeln('│───────┼───────┼───────│'),
    !,
    prettier_print(9, Puzzle).
prettier_print(12, []) :-
    writeln('└───────┴───────┴───────┘'),
    !.
prettier_print(N, [Col1, Col2, Col3, Col4, Col5, Col6, Col7, Col8, Col9 | Puzzle]) :-
    member(N, [1,2,3,5,6,7,9,10,11]),  % tried this when the line below did not work

    format('│ ~d ~d ~d │ ~d ~d ~d │ ~d ~d ~d │~n', [Col1, Col2, Col3, Col4, Col5, Col6, Col7, Col8, Col9]),
    succ(N, N1),
    prettier_print(N1, Puzzle),
    !.

您也可以重写您的解决方案,以便通过使用其他谓词而不是prettier_print的不同子句来保留任何选择点。这样你就不需要使用剪切:

prettier_print(Puzzle) :-
  Puzzle \= [] ->
  (
    print_head,
    print_rows(Puzzle, NRows1),
    print_line,
    print_rows(Puzzle, NRows1),
    print_line,
    print_rows(Puzzle, NRows1),
    print_end
  ).

print_rows(Rows, NRows):-
  print_row(Rows, Rows1),
  print_row(Rows1, Rows2),
  print_row(Rows2, NRows).

print_head:-
    writeln('┌───────┬───────┬───────┐').

print_line:-
    writeln('│───────┼───────┼───────│').

print_end:-
    writeln('└───────┴───────┴───────┘').

print_row([Col1, Col2, Col3, Col4, Col5, Col6, Col7, Col8, Col9 | NRows], NRows) :-
    format('│ ~d ~d ~d │ ~d ~d ~d │ ~d ~d ~d │~n', [Col1, Col2, Col3, Col4, Col5, Col6, Col7, Col8, Col9]).

答案 3 :(得分:0)

Augh,没关系,我是个白痴!

我首先确定了一些不成问题的东西。将prettier_print/1更改为此:

prettier_print([]).
prettier_print(Puzzle) :- prettier_print(0, Puzzle).

使其正常工作。

我仍然想知道为什么它会返回true而不是false。如果有人可以回答,我会标记他们的答案被接受。

相关问题