基于Prolog的模式匹配问题

基于Prolog的模式匹配问题,prolog,pattern-matching,backtracking,Prolog,Pattern Matching,Backtracking,编辑:查看下面我的答案,了解我为什么是傻瓜。不过,这里面还有一个谜,我很想回答 我在这件事上纠缠太久了。我正试图在一个漂亮的网格中打印出一个数独解决方案 我想我遇到了一些问题,因为我不理解模式匹配在Prolog中是如何工作的 不用多说,我的代码: prettier_print([]). prettier_print([Puzzle]) :- prettier_print(0, [Puzzle]). prettier_print(0, Puzzle) :- writeln('┌────

编辑:查看下面我的答案,了解我为什么是傻瓜。不过,这里面还有一个谜,我很想回答

我在这件事上纠缠太久了。我正试图在一个漂亮的网格中打印出一个数独解决方案

我想我遇到了一些问题,因为我不理解模式匹配在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\u print/1
规则不能正常工作

我想我知道的足够多了,这意味着:

Prolog正在回溯并尝试对我的规则进行另一种解释(如果我正确理解了我的术语,看看是否还有其他可以统一的东西)。这发现了另一个与之相统一的东西,但它马上就失败了。是这样吗

我希望只有一种可能的解释。我如何修正我的函数,使之成为那样


谢谢你的帮助,这让我觉得自己像个傻瓜

哦,别担心,我是个白痴

我一开始就指出了一些不是问题的东西。将
prettier\u print/1
更改为:

prettier_print([]).
prettier_print(Puzzle) :- prettier_print(0, Puzzle).
使它工作良好


我仍然想理解为什么它会先返回真的,然后返回假的。如果有人能回答,我会将他们的答案标记为接受。

要了解这一点,请尝试SWI Prolog的图形跟踪:

?- gtrace, your_goal.
跟踪器将向您显示选择点的创建位置,引入非确定性。在回溯时(例如,当您在顶层按空格或“;”时),将考虑剩余的备选子句。

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

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

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

如果您不想看到
false
消息,请不要回溯,即按Enter键而不是
,或使用元谓词
一次/1

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

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

?- 

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

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

您可以“剪切”回溯,通过使用剪切(!)提交到一个选项:

您也可以重写您的解决方案,以便通过使用一些其他谓词而不是不同的子句来更好地打印,从而不留下任何选择点。这样,您就不需要使用切割:

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]).

很好的解释,这正是我需要的,谢谢!你似乎至少误读了我问题的一部分。为了澄清这一点,我知道什么是
是的,我知道REPLs通常的行为。我使用过的许多函数(或规则?)甚至在交互式解释器中也可以简单地打印出一个正确的答案。我写的这篇文章没有这样做,我也不知道为什么。这是我困惑的核心。一开始,我还错误地认为这是导致prettier_print/1规则不起作用的原因,但我设法澄清了这一点。谢谢你的回答,谢谢你的帮助。
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]).