我正在为我的prolog课程工作,但我仍然坚持如何处理逻辑谜题的一些线索,并非常感谢一些提示/技巧/帮助:
比利,费尔南多,史蒂文和扎卡里都预约了医生。不幸的是,医生的计算机系统崩溃了,他/她不记得谁有背痛,胃灼热,臀部疼痛或带状疱疹,以及预约是在上午9点,上午10点,上午11点还是12点。但幸运的是,发现以下线索:到目前为止,我有这个,但看到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,所以感谢你有任何麻烦。
答案 0 :(得分:1)
这里有几个问题。首先,Prolog原子总是小写或引用; Billy
和Fernando
等是变量,可能不是您想要的变量,因此您需要修复它。
其次,这里有一些令人困惑的代码:
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/1
,time/1
和ailment/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,所以你失败了,因为你生成的唯一解决方案没有成功。