Prolog列表拼图

时间:2015-12-15 12:12:18

标签: list prolog logic membership

我正在为我的prolog课程工作,但我仍然坚持如何处理逻辑谜题的一些线索,并非常感谢一些提示/技巧/帮助:

比利,费尔南多,史蒂文和扎卡里都预约了医生。不幸的是,医生的计算机系统崩溃了,他/她不记得谁有背痛,胃灼热,臀部疼痛或带状疱疹,以及预约是在上午9点,上午10点,上午11点还是12点。但幸运的是,发现以下线索:

  • 患有胃灼热和比利的人,一人有1100人预约,另一人有0900年预约。
  • 胃灼热患者在髋关节疼痛患者后2小时预约。
  • 带状疱疹病人是比利或费尔南多
  • Zachary在背部疼痛患者之后的某个时间预约了。

到目前为止,我有这个,但看到zachary谓词如何导致无限循环,我相当肯定我对它有错误的方法。

sublist( [], _ ).
sublist( [X|XS], [X|XSS] ) :- sublist( XS, XSS ).
sublist( [X|XS], [_|XSS] ) :- sublist( [X|XS], XSS ).

ziekte(X,Y,Z):-
    Appointments = [0900,1000,1100,1200],
    member(ziekte(Billy,_),Appointments),
    member(ziekte(Fernando,_),Appointments),
    member(ziekte(Steven,_),Appointments),
    member(ziekte(Zachary,_),Appointments),
    sublist([ziekte(Billy,_),ziekte(_,heartburn)],[0900,1100]),
    sublist([ziekte(Billy,shingles),ziekte(Fernando,shingles)],Appointments).

ziekte(_,back-pain,Y) :-
    ziekte(Zachary,_,X),
    X > Y.

ziekte(_,hip-pain,0900) :-
    ziekte(_,heartburn,1100).

ziekte(_,hip-pain,1000) :-
    ziekte(_,heartburn,1200).

我发现自己很难绕过Prolog,所以感谢你有任何麻烦。

1 个答案:

答案 0 :(得分:1)

这里有几个问题。首先,Prolog原子总是小写或引用; BillyFernando等是变量,可能不是您想要的变量,因此您需要修复它。

其次,这里有一些令人困惑的代码:

Appointments = [0900,1000,1100,1200],
member(ziekte(Billy,_),Appointments),

您在这里说的是,"我有一个数字列表,[900,1000,1100,1200]ziekte(V1,_)就在其中。"这显然是错误的 - 此列表中没有ziekte/2个结构。

我怀疑你可能患有Prolog开始程序员最常见的疾病:相信Prolog关系"返回"值。你认为ziekte(Billy,_)会以某种方式导致ziekte/3在下面被调用,并且该关系的第三个参数会以某种方式出现在这个位置吗?它不会 - 结构ziekte(_,_)和下面定义的谓词ziekte/3之间没有关系,而Prolog根本不会评估这样的嵌套表达式。

member(X, List)做什么?它会尝试使用X的每个值统一 List。假设您有一个类似L = [appointment(zachary,back-pain,1100), appointment(steven,X,Y), appointment(Z,heartburn,900), ...]的列表。 member(appointment(billy,Ailment,900), L)做了什么?它试图统一:

appointment(billy,Ailment,900) = appointment(zachary,back-pain,1100)
  fails
appointment(billy,Ailment,900) = appointment(steven,X,Y)
  fails
appointment(billy,Ailment,900) = appointment(Z,heartburn,900)
  succeeds with
    Ailment = heartburn
    Z = billy

如果你觉得这很令人惊讶,你需要更加努力地思考统一!

你有无限递归的原因是你的谓词ziekte/3自称。查看跟踪:

trace, ziekte(X,Y,Z).
   Call: (8) ziekte(_G4078, _G4079, _G4080) ? 
   Call: (9) _G4239=[900, 1000, 1100, 1200] ? 
   Exit: (9) [900, 1000, 1100, 1200]=[900, 1000, 1100, 1200] ? 
   Call: (9) lists:member(ziekte(_G4232, _G4233), [900, 1000, 1100, 1200]) ? 
   Fail: (9) lists:member(ziekte(_G4232, _G4233), [900, 1000, 1100, 1200]) ? 
   Redo: (8) ziekte(_G4078, _G4079, _G4080) ? 
   Call: (9) ziekte(_G4230, _G4231, _G4232) ? 
   Call: (10) _G4242=[900, 1000, 1100, 1200] ? 
   Exit: (10) [900, 1000, 1100, 1200]=[900, 1000, 1100, 1200] ? 
   Call: (10) lists:member(ziekte(_G4235, _G4236), [900, 1000, 1100, 1200]) ? 
   Fail: (10) lists:member(ziekte(_G4235, _G4236), [900, 1000, 1100, 1200]) ? 
   Redo: (9) ziekte(_G4230, _G4231, _G4232) ? 
   Call: (10) ziekte(_G4233, _G4234, _G4235) ? 
   Call: (11) _G4245=[900, 1000, 1100, 1200] ? 
   Exit: (11) [900, 1000, 1100, 1200]=[900, 1000, 1100, 1200] ? 
   Call: (11) lists:member(ziekte(_G4238, _G4239), [900, 1000, 1100, 1200]) ? 
   Fail: (11) lists:member(ziekte(_G4238, _G4239), [900, 1000, 1100, 1200]) ? 
   Redo: (10) ziekte(_G4233, _G4234, _G4235) ? 

这里发生的是:您想要输入ziekte(X,Y,Z)。 Prolog找到第一个条款,即头部ziekte(X,Y,Z)。它立即形成约会时间列表。然后它检查是否有ziekte/2结构。这失败了。 Prolog回溯并尝试下一个子句:头部为ziekte(_,back-pain,Y)的子句。该子句正文中的第一个表达式是ziekte(Zachary,_,X)。我们再说一遍:Prolog找到ziekte的第一个条款,我们就回到了我们开始的地方。

现在你还有其他问题。请注意,您会收到很多单例变量警告。开始将这些视为致命错误。

你的规则条款对我来说非常奇怪。坦白说,我不知道他们怎么可能工作。

我觉得你在这里很丢失!我强烈建议你复习Prolog的基础知识。你不能伪造它直到用Prolog制作它,它真的与其他一切完全不同!

如果我是你,我会首先使用patient/1time/1ailment/1这样的事实来制定域名。我在我的解决方案中大量使用了select/3,所以我会对此进行审核。还plus/3。确保您对结构之间的差异(和相似性)有一个具体的了解 - 评估何时发生,何时不发生。然后回来再试一次!

编辑关于pastebin代码的评论。

粘贴代码的主要问题是您尝试使用sublist/2生成排列,但它的作用是为您提供有序的子集。您第一次通过您已经生成了一个解决方案集,该解决方案集失败了,然后您将剩余的时间用在sublist/2

检查出来:

?- ziekte(Y), sublist([Y1,Y2,Y3,Y4], Y).
Y = [backpain, heartburn, hippain, shingles],
Y1 = backpain,
Y2 = heartburn,
Y3 = hippain,
Y4 = shingles ;
false.

这只有一个解决方案,所以你只是真正尝试一种排列。当您点击member([billy,_,Tijd1], Opl)时,您已经设置了Opl = [[billy, backpain, 900], [fernando, heartburn, 1000], [steven, hippain, 1100], [zachary, shingles, 1200]]。如果您使用某些内容来置换列表以生成不同的分配,这样会很好,但前面的sublist/2调用没有更多解决方案,因此X1..X4,Y1..Y4将不会有任何其他分配,Z1..Z4,所以你失败了,因为你生成的唯一解决方案没有成功。