Prolog中如何遍历检查所有row、Column、number形式的cell事实?
问题:怎样正确遍历Prolog里的cell单元格事实?
我手头有一批用Prolog事实表示的单元格数据,每个cell/3事实包含行号、列号和对应单元格里的数字,想实现类似普通数组遍历的逻辑来检查这些单元格。我自己写了一段代码,但不仅跑不起来,还没法遍历到所有事实:
allcolored(X,Y) :- cell(X,Y,_), X1 is X - 1, Y1 is Y - 1, allcolored(X1,Y1).
问题出在哪?
这段代码有两个致命问题:
- 没有终止条件:递归会一直把X和Y减1,直到变成负数,这时候找不到对应的
cell事实,直接就失败了,根本走不完所有可能的单元格。 - 遍历范围完全错了:你现在的逻辑是从(X,Y)往左上对角线递归,只能遍历到(X,Y)、(X-1,Y-1)这类在同一条对角线上的单元格,其他行或列的单元格根本碰不到。
给你两种可行的遍历方案
方案1:利用Prolog回溯特性快速遍历所有单元格
Prolog本身的回溯机制天生适合枚举所有事实,我们可以利用这个特性来遍历:
traverse_cells :- % 匹配一个cell事实 cell(X, Y, Num), % 这里写你对每个单元格的检查逻辑,比如打印出来看看 format('正在检查单元格(~w,~w): 数字是~w~n', [X,Y,Num]), % 用fail触发回溯,让Prolog去找下一个cell fail. % 所有cell都遍历完后,这个子句会成功,结束遍历 traverse_cells.
调用traverse_cells.就能遍历所有cell事实,每匹配一个就执行你的检查操作,直到所有事实都被处理完。
方案2:按行/列的顺序遍历(模拟数组的遍历顺序)
如果需要像普通数组那样,先遍历第一行的所有列,再遍历第二行,这种有顺序的遍历,可以用下面的写法:
% 获取所有不重复的行号,排序后保证顺序 all_rows(Rows) :- findall(R, cell(R, _, _), TempRows), sort(TempRows, Rows). % 获取某一行对应的所有列号,同样排序 row_cols(Row, Cols) :- findall(C, cell(Row, C, _), TempCols), sort(TempCols, Cols). % 入口谓词:按行遍历所有单元格 traverse_by_rows :- all_rows(Rows), traverse_rows_list(Rows). % 遍历行列表的递归终止条件:行列表为空时结束 traverse_rows_list([]). % 遍历每一行:先处理当前行的所有列,再处理剩下的行 traverse_rows_list([CurrentRow|RestRows]) :- row_cols(CurrentRow, Cols), traverse_row_columns(CurrentRow, Cols), traverse_rows_list(RestRows). % 遍历某一行的列列表的终止条件 traverse_row_columns(_, []). % 遍历当前行的每一列:处理单元格,再处理下一列 traverse_row_columns(Row, [CurrentCol|RestCols]) :- cell(Row, CurrentCol, Num), format('检查单元格(~w,~w): 数字是~w~n', [Row,CurrentCol,Num]), traverse_row_columns(Row, RestCols).
这个方案会先把所有行号排序,然后逐行遍历每个行里的所有列,完全模拟普通二维数组的遍历顺序。
内容的提问来源于stack exchange,提问作者Makdous
相关产品推荐
相关产品推荐

