首页 > 解决方案 > Prolog失败一次就放弃了?

问题描述

我还在学习 Prolog,如果我在这里犯了一些基本错误,请原谅我。我添加了注释来解释我认为代码在做什么,以防我错了。如果我在某些地方解释显而易见的事情,请原谅我。

n_queens(NumQueens, Answer) :-
        length(Answer, NumQueens), %Answer must be a list of length NumQueens
        queens_are_safe(Answer). %All queens in Answer must be safe       

queens_are_safe([]). %If there are no queens, nobody's in danger
queens_are_safe([Queen | Queens]) :-
        queen_is_safe(Queen, Queens), %Is the queen safe from her peers?
        queens_are_safe(Queens). %Recursively check the other queens

queen_is_safe(_, []).
queen_is_safe(NewQueen, [Queen | Queens]) :-
        not(same_column(NewQueen, Queen)),
        not(same_row(NewQueen, Queen)),
        not(diagonal(NewQueen, Queen)),
        queen_is_safe(NewQueen, Queens). %Recursively ensure NewQueen is safe from other queens

diagonal(X/Y, X1/Y1) :- Y1 - Y = X1 - X. %If the X and Y deltas are equal, arguments are diagonal
same_column(X/_, X/_). %If the X coordinates are the same, it's the same column.
same_row(_/Y, _/Y). %If the Y coordinates are the same, it's the same row.

我期望 Prolog 做的是生成一个皇后列表,将其绑定到 Answer,然后重复,直到找到满足所有条件的值列表。例如,如果 NumQueens 为 2,它将测试 [0/0, 0/0],然后是 [1/0, 0/0],依此类推。

但是我怀疑我在这里大错特错。跟踪堆栈在这里失败:

Exit: (12) samecolumn(_15108/_15110, _15108/_15116) ? creep
Fail: (11) not(user:samecolumn(_15048, _15054)) ? creep

显然问题在于它使用_15108 作为same_column 的X 值。我希望它然后尝试 same_column 但使用不同的 X 值。但它不会再试一次,它会失败并为查询返回 falsen_queens(8,Ans).为什么会这样?

标签: prolog

解决方案


尝试在 SWI-Prolog 中运行代码时出现以下错误:

?- n_queens(8, Ans).
ERROR: not/1: Undefined procedure: samecolumn/2
ERROR:   However, there are definitions for:
ERROR:         same_column/2

您是否使用了在尝试调用未定义谓词时静默失败的 Prolog?您不应该,或者您应该将其配置为在这种情况下引发错误。例如,在 YAP 中,默认行为是您看到的损坏的行为:

   ?- n_queens(8, Ans).
no

但是你可以像这样修复它:

   ?- set_prolog_flag(unknown, error).
yes
   ?- n_queens(8, Ans).
     ERROR!!
     EXISTENCE ERROR- procedure samecolumn/2 is undefined, called from context  prolog:$query/2
                 Goal was user:samecolumn(_131242,_131243)

编辑:只是为了明确这一点,如消息所示,直接的问题之一是您试图调用samecolumn/2未定义的谓词;你可能打算打电话给same_column/2.

Y1 - Y = X1 - X在此之后,由于diagonal/2. 例如,您可能希望diagonal(2/3, 3/4)成功,但目标在 Prolog4 - 3 = 3 - 2没有成功:

?- 4 - 3 = 3 - 2.
false.

这是因为 Prolog 不将类似的项4 - 3视为算术表达式来计算为类似的数字1。您可能需要将=:=两个操作数都计算为数字然后比较它们的运算符:

?- 4 - 3 =:= 3 - 2.
true.

但即使在这一切之后,这段代码也行不通。您的程序从不指定应该将 中的变量Queens绑定到整数1的任何地方NumQueens。Prolog 不只是为您编造这些数字!您可能想使用clpfd.


推荐阅读