Prolog列表拼图

Prolog list puzzle

我正在为我的 prolog 课程做作业,但我仍然停留在如何处理逻辑谜题的一些线索上,非常感谢一些 hints/tricks/assistance:

比利、费尔南多、史蒂文和扎卡里都预约了医生。不幸的是,医生的计算机系统崩溃了,s/he 不记得谁有背痛、胃灼热、臀部疼痛或带状疱疹,也记不起约会时间是上午 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,所以感谢您解决任何问题。

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

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

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) 是做什么的?它试图 统一 XList 的每个值。假设您有一个类似于 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, 所以你失败了,因为你生成的唯一解决方案没有成功。