Prolog列表拼图
Prolog list puzzle
我正在为我的 prolog 课程做作业,但我仍然停留在如何处理逻辑谜题的一些线索上,非常感谢一些 hints/tricks/assistance:
比利、费尔南多、史蒂文和扎卡里都预约了医生。不幸的是,医生的计算机系统崩溃了,s/he 不记得谁有背痛、胃灼热、臀部疼痛或带状疱疹,也记不起约会时间是上午 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,所以感谢您解决任何问题。
这里有几个问题。首先,Prolog 原子总是小写或引用; Billy
和 Fernando
等是变量,这可能不是您想要的,因此您需要修复它。
其次,这里有一些令人困惑的代码:
Appointments = [0900,1000,1100,1200],
member(ziekte(Billy,_),Appointments),
你在这里说的是,"I have a list of numbers, [900,1000,1100,1200]
, and ziekte(V1,_)
is in it." 这显然是错误的——此列表中没有 ziekte/2
结构。
我怀疑您可能患有 Prolog 程序员新手最常见的毛病:相信 Prolog 关系 "return" 值。你认为 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, 所以你失败了,因为你生成的唯一解决方案没有成功。
我正在为我的 prolog 课程做作业,但我仍然停留在如何处理逻辑谜题的一些线索上,非常感谢一些 hints/tricks/assistance:
比利、费尔南多、史蒂文和扎卡里都预约了医生。不幸的是,医生的计算机系统崩溃了,s/he 不记得谁有背痛、胃灼热、臀部疼痛或带状疱疹,也记不起约会时间是上午 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,所以感谢您解决任何问题。
这里有几个问题。首先,Prolog 原子总是小写或引用; Billy
和 Fernando
等是变量,这可能不是您想要的,因此您需要修复它。
其次,这里有一些令人困惑的代码:
Appointments = [0900,1000,1100,1200],
member(ziekte(Billy,_),Appointments),
你在这里说的是,"I have a list of numbers, [900,1000,1100,1200]
, and ziekte(V1,_)
is in it." 这显然是错误的——此列表中没有 ziekte/2
结构。
我怀疑您可能患有 Prolog 程序员新手最常见的毛病:相信 Prolog 关系 "return" 值。你认为 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, 所以你失败了,因为你生成的唯一解决方案没有成功。