List 序言列表难题

List 序言列表难题,list,prolog,logic,membership,List,Prolog,Logic,Membership,我正在为我的prolog课程做一项作业,但我一直在思考如何处理逻辑谜题的一些线索,非常希望得到一些提示/技巧/帮助: 比利、费尔南多、史蒂文和扎卡里都在医生那里预约了。不幸的是,医生的计算机系统出现故障,他/她不记得谁有背痛、胃灼热、臀部疼痛或带状疱疹,也不记得预约时间是上午9点、10点、11点还是12点。但幸运的是,我们发现了以下线索: 在胃灼热和比利的患者中,一人有1100个预约,另一人有0900个预约 胃灼热患者在髋部疼痛患者2小时后预约 带状疱疹患者不是比利就是费尔南多 扎卡里在背痛病

我正在为我的prolog课程做一项作业,但我一直在思考如何处理逻辑谜题的一些线索,非常希望得到一些提示/技巧/帮助:

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

  • 在胃灼热和比利的患者中,一人有1100个预约,另一人有0900个预约
  • 胃灼热患者在髋部疼痛患者2小时后预约
  • 带状疱疹患者不是比利就是费尔南多
  • 扎卡里在背痛病人出院后有个约会
到目前为止,我有这个,但看到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).

我发现自己很难理解序言,所以感谢您给我带来的麻烦。

这里有几个问题。首先,序言原子总是小写或引用
Billy
Fernando
等都是变量,这可能不是您想要的,所以您需要解决这个问题

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

Appointments = [0900,1000,1100,1200],
member(ziekte(Billy,_),Appointments),
你在这里说的是,“我有一个数字列表,
[900100011001200]
,其中有
ziekte(V1,)
。”这显然是错误的——这个列表中没有
ziekte/2
结构

我怀疑您可能正遭受着初级Prolog程序员最常见的疾病:相信Prolog关系“返回”值。您是否认为
ziekte(Billy,41;
会以某种方式导致下面调用
ziekte/3
,并且该关系的第三个参数会以某种方式出现在该位置?它不会——在结构
ziekte(,)
和下面定义的谓词
ziekte/3
之间没有关系,Prolog根本不会对这样的嵌套表达式求值

成员(X,列表)
做什么?它试图将
X
List
的每个值统一起来。假设您有一个列表,看起来像
L=[约会(扎卡里,背痛,1100),约会(史蒂文,X,Y),约会(Z,heartburn,900),…]
会员(预约(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(u,背部疼痛,Y)的子句。本子句正文中的第一个表达式是
ziekte(Zachary,ux)
。我们重复:Prolog找到了
ziekte
的第一个子句,我们回到了开始的地方

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

我觉得你的规则条款非常奇怪。坦率地说,我不知道它们怎么可能起作用

我想你在这里迷路了!我强烈建议您复习Prolog的基础知识。在使用Prolog之前,你不能伪造它,它真的与其他东西完全不同

如果我是你,我会先用
patient/1
time/1
ailment/1
等事实来描绘这个领域。我在解决方案中大量使用了
select/3
,因此我将对此进行回顾。另外
plus/3
。确保您对结构之间的差异(和相似性)有一个具体的理解——何时进行评估,何时不进行评估。然后回来再试一次

编辑:对pastebin代码的注释

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

看看这个:

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

这只有一个解决方案,所以您实际上只尝试一种排列。当您与
成员([billy,u,Tijd1],Opl)]
联机时,您已经设置了
Opl=[[billy,backpain,900],[fernando,heartburn,1000],[steven,hippain,1100],[zachary,shingles,1200]
。如果您正在使用某些东西来排列列表以生成不同的分配,这将是很好的,但是前面的
子列表/2
调用没有更多的解决方案,因此不会有任何其他分配给X1..X4,Y1..Y4,Z1..Z4,因此您失败了,因为您生成的唯一解决方案没有成功。

非常感谢,我从一个不同问题的解决方案(类似的结构问题,但关于有宠物的房子)中得到了总体结构。。我会把你的建议放在心上,这次我会自己从头开始,再次感谢你。嗨,丹尼尔·莱昂斯,在另一次尝试理解序言时,我试着重做作业()。。虽然(我认为)我越来越接近解决方案(在很大程度上要感谢你,再次感谢),但我现在有一个问题,就是有太多的Billie过来了(我想这与第一个和第三个关于billy的提示有关)。如果你能抽出时间再次向它展示你的光芒,我将不胜感激。我已经编辑了我的答案,对你的新代码进行了一些讨论。你是我的朋友