我有以下代码:
word(aa, a, a).
word(ab, a, b).
word(ac, a, c).
word(ad, a, d).
word(bb, b, b).
word(bc, b, c).
word(bd, b, d).
word(cc, c, c).
word(cd, c, d).
word(dd, d, d).
word(dc, d, c).
null(a).
crossword(A, B, C, D) :-
word(A, AC, AD),
word(B, BC, BD),
word(C, AC, BC),
word(D, AD, BD),
A \== B,
B \== C,
A \== C,
B \== D,
C \== D,
writeln(A-B-C-D),
null(b).
这是一个prolog代码,用于获取填充2x2单词表的所有可能方法,如下所示:
我想知道如何查询此代码以获取所有答案。我无法弄清楚null(a)
和null(b)
的用途是什么?
答案 0 :(得分:1)
以下是现有代码的细分。
word(aa, a, a).
...
word(dd, d, c).
word(dc, d, c).
这些定义word
个事实似乎列出了有效的“单词”。额外的第二和第三个参数似乎是多余的,因为(a)它们很容易从第一个参数派生,并且(b)它们不会在所示程序中的任何地方使用(从摘录中不清楚是否还有其他部分程序)。同样不清楚为什么列出了cd
和dc
,但是没有给出其他“单词”的对称关系。
null(a).
这是一个事实,说“a
是null
”,但鉴于上下文有限,语义不明确。
crossword(A, B, C, D) :-
这是一个谓词crossword/4
,它接受4个参数。有这些论点的原因尚不清楚(见下文)。
word(A, AC, AD),
word(B, BC, BD),
word(C, AC, BC),
word(D, AD, BD),
以上4行代码收集了4个字的事实。你可以在使用AC
,AD
等时看到一个依赖关系,它确保一对词是跨越的,而另一对词是你得到的那些词。在董事会上向下阅读相同的单词。
A \== B,
B \== C,
A \== C,
B \== D,
C \== D,
以上5行代码确保收集的单词事实之间存在一些差异。同样,语义不清楚,因为它允许A
和D
是同一个单词(考虑到其他约束,可能不是这样)。如果这些不平等测试中的任何一个失败,那么回溯将发生回上面的word/3
查询以收集至少一个不同的单词事实,而Prolog将重试不等式检查。
writeln(A-B-C-D),
这写出了满足所有上述不等式的“单词”的当前四元组。
null(b).
此测试(查询)将失败的事实null(b)
,因为null(b)
未被建立为事实或可从null(X)
的任何给定规则派生。当它失败时,Prolog将再次回溯到通过word/3
查询收集另一组单词事实。
当word/3
查询的所有组合都已用尽时(每个组合都提供了几个单词事实中的一个作为解决方案),整个crossword/4
谓词在显示所有可能性后失败并结束与writeln
。因此,当您发出查询crossword(A, B, C, D).
时,它会依据上面的writeln
继续迭代并显示每个可能的解决方案,直到不再存在解决方案并最终失败(意味着,没有更多解决方案)。
正如我在评论中提到的,代码有点奇怪。例如,使用null(b)
作为无效事实导致代码通过回溯继续迭代。也许最初的意图是在需要时将事实null(a)
更改为null(b)
以“关闭迭代”。有点像“迭代标志”。根据给出的信息,这是不确定的。
构建代码的另一种方法是:
crossword(A, B, C, D) :-
word(A, AC, AD),
word(B, BC, BD),
word(C, AC, BC),
word(D, AD, BD),
A \== B,
A \== C,
B \== C,
B \== D,
C \== D.
当使用crossword(A, B, C, D)
查询时,Prolog将单独为您提供每个解决方案,直到找不到为止,或者您告诉它停止。您可以使用setof
setof(A-B-C-D, crossword(A, B, C, D), Solutions).