首页 > 解决方案 > 获得“独特”绑定的更简单方法?

问题描述

对不起,如果我的术语是关闭的。长期(40 年?哎哟......)命令式程序员,涉足函数式,今天早上花了一些时间尝试更认真地对待声明式。浏览一个学习网站,并决定在这里尝试练习 2.4 中的“填字游戏”:http: //www.learnprolognow.org/lpnpage.php? pagetype=html&pageid=lpn-htmlse7

我知道了,但感觉非常笨拙。这是我的新手解决方案:

word(astante,  a,s,t,a,n,t,e).
word(astoria,  a,s,t,o,r,i,a).
word(baratto,  b,a,r,a,t,t,o).
word(cobalto,  c,o,b,a,l,t,o).
word(pistola,  p,i,s,t,o,l,a).
word(statale,  s,t,a,t,a,l,e).

crossword(V1,V2,V3,H1,H2,H3):-
    word(V1,V1a,V1b,V1c,V1d,V1e,V1f,V1g),
    word(V2,V2a,V2b,V2c,V2d,V2e,V2f,V2g),
    word(V3,V3a,V3b,V3c,V3d,V3e,V3f,V3g),
    word(H1,H1a,H1b,H1c,H1d,H1e,H1f,H1g),
    word(H2,H2a,H2b,H2c,H2d,H2e,H2f,H2g),
    word(H3,H3a,H3b,H3c,H3d,H3e,H3f,H3g),
    V1b = H1b,
    V1d = H2b,
    V1f = H3b,
    V2b = H1d,
    V2d = H2d,
    V2f = H3d,
    V3b = H1f,
    V3d = H2f,
    V3f = H3f,
    not(V1 = V2),
    not(V1 = V3),
    not(V1 = H1),
    not(V1 = H2),
    not(V1 = H3),
    not(V2 = V3),
    not(V2 = H1),
    not(V2 = H2),
    not(V2 = H3),
    not(V3 = H1),
    not(V3 = H2),
    not(V3 = H3),
    not(H1 = H2),
    not(H1 = H3),
    not(H2 = H3).

有用。填字游戏会给我两种可能的布局(毕竟拼图是对称的)。但是是的...

有些笨拙只是因为我才刚刚开始,所以我对如何将绑定标记为“不关心”没有任何感觉(单词的第 1、3、5 和第 7 个字母完全不相关, 例如)。但现在真正让我恼火的是必须在最后放入“不要重复任何绑定”的三角矩阵。这个问题不断出现(早期的玩具问题涉及爱(A,B)和嫉妒(X,Y),如果你允许 X=Y,那么每个开始恋爱关系的人都会被声称嫉妒自己(我看到有人else 几年前正在与之抗争:使用 Prolog 获得独特的结果)),但本教程没有解决它。它甚至还没有告诉我“不”——我不得不在其他地方挖掘才能得到它,这导致了“好吧,你想要什么样的'不相等'?”的完全有效的问题,我就是目前还没有准备好回答。但我离题了...

这对我来说是不可思议的,这是在实际代码中实际完成的方式。结合起来,这很荒谬。它似乎违反(或至少弯曲)了最不惊讶的原则。没有唯一性限制,有大量的解决方案只是设置 V1=H1,V2=H2,V3=H3。我想我只能禁止这些,但真正的解决方案需要完全限制。

是的,我完全理解从逻辑和数学上讲,没有理由不将相同的值绑定到多个参数中,而且在很多情况下,这样的多重绑定不仅有帮助,而且需要处理手头的问题。我根本不是在争论默认行为,只是在需要时寻找一种更好的方式来表达唯一性约束。

我很想知道一种更好的方法来处理这个问题,因为老实说,如果这些教程都需要这么多的绒毛来做一些看似显而易见的事情,我认为我不能更深入地研究这些教程。

提前致谢!

标签: prolog

解决方案


在我看来,这个练习会让你走向失败

首先,因为它使用的知识表示不适合以统一的方式处理相似的元素。

其次,因为您在本书的这一点上没有必要的先决条件来这样做,即使知识表示会使它变得更容易。

我可以向你保证:在 Prolog 中编程时,你所做的当然是不必要的。

所以,不要让一本书减损你的语言。

在这一点上,我想向您展示如果您有更多的语言经验并使用更合适的语言功能,您将如何解决此任务当您阅读其他材料时,您可能会喜欢稍后再回到这里。

我想做的关键改变是让您更明确地推理可用的单词,作为程序中可用的数据结构而不是“仅”作为事实:

单词(WS):-
        Ws = [[a,s,t,a,n,t,e],
              [a,s,t,o,r,i,a],
              [b,a,r,a,t,t,o],
              [c,o,b,a,l,t,o],
              [p,i,s,t,o,l,a],
              [s,t,a,t,a,l,e]]。

当然,您可以使用全解谓词(例如.findall/3

我现在介绍的关键谓词让我们将这个表示中的一个词与它的每个第二个字母联系起来:

word_evens([_,A,_,B,_,C,_], [A,B,C])。

请注意,如果您可以明确地推理构成单词的字母列表,则可以轻松地表达这种关系。

现在,整个解决方案使用谓词permutation/2and transpose/2,您可以在 Prolog 系统中将其作为库谓词找到,也可以自己轻松实现:

解决方案(Ls): -
        Ls = [V1,V2,V3,H1,H2,H3],
        单词(Ws),
        Ws = [第一|_],
        maplist(same_length(First), Ls),
        maplist(word_evens, [H1,H2,H3], Ess),
        转置(Ess,TEss),
        maplist(word_evens, [V1,V2,V3], TEss),
        排列(Ws,Ls)。

示例查询和两种解决方案:

?- 解决方案(Ls)。
Ls = [[a, s, t, a, n, t, e], [c, o, b, a, l, t, o], [p, i, s, t, o, l|.. .], [a, s, t, o, r|...], [b, a, r, a|...], [s, t, a|...]] ;
Ls = [[a, s, t, o, r, i, a], [b, a, r, a, t, t, o], [s, t, a, t, a, l|.. .], [a, s, t, a, n|...], [c, o, b, a|...], [p, i, s|...]] ;
错误的。

至少maplist/2应该在您的 Prolog 中可用,并且same_length/2如果您的系统不提供它很容易定义。

如果您真的想表达术语的不等式,请使用


推荐阅读