【问题标题】:Prolog beginner, combining rules question?Prolog初学者,结合规则问题?
【发布时间】:2023-03-27 13:32:01
【问题描述】:

我正在尝试根据这些事实编写一个程序:

博伊尔生于 1627 年,死于 1691 年。 牛顿生于 1642 年,死于 1727 年。 (等等)

我想创建一个规则来确定一个人在指定年份是否还活着。到目前为止,这是我想出的:

scientist(boyle, 1627, 1691).
scientist(newton, 1642, 1727).
alive_after(X) :- scientist(A, B, C), B < X.
alive_before(X) :- scientist(A, B, C), C > X.
alive_during(X, Year) :- alive_after(X), alive_before(X).

我相信我的前两条规则是正确的,但是当我将它们组合成我的 alive_during 规则时,它们似乎并没有按预期工作。当我将此作为输入运行我的代码时:

alive_during(1628).
X = boyle

它不起作用。 我在这里错过了什么?

【问题讨论】:

    标签: prolog


    【解决方案1】:

    Prolog 无法统一隐藏在谓词主体中的变量。 alive_after/1 中的Aalive_before/1 中的A 之间没有关系。 Prolog 实际上告诉你,当它报告这些警告时它不知道你在做什么:`

    |: alive_after(X) :- scientist(A, B, C), B < X.
    Warning: user://2:19:
        Singleton variables: [A,C]
    |: alive_before(X) :- scientist(A, B, C), C > X.
    
    Warning: user://2:23:
        Singleton variables: [A,B]
    |: alive_during(X, Year) :- alive_after(X), alive_before(X).
    
    Warning: user://2:27:
        Singleton variables: [Year]
    

    极其重要将这些消息视为错误尤其是在您刚接触 Prolog 时!

    解决方案是让 Prolog 能够跨这些谓词统一科学家:

    alive_after(Scientist, Year)  :- scientist(Scientist, Birth, _), Year > Birth.
    alive_before(Scientist, Year) :- scientist(Scientist, _, Death), Year < Death.
    alive_during(Scientist, Year) :- 
        alive_before(Scientist, Year), alive_after(Scientist, Year).
    

    您可能还会发现,当您为变量指定有意义的名称时,遵循逻辑会更容易一些。在编写非常通用的谓词时,我对使用极其简洁的变量名感到内疚,但这些实际上是非常具体的谓词,一个好的名称可以帮助您理解您正在做的事情的结构。会是,我认为这比你写的更正确:

    alive_after(A, X)  :- scientist(A, B, _), X > B.
    alive_before(A, X) :- scientist(A, _, C), X < C.
    alive_during(A, X) :- alive_before(A, X), alive_after(A, X).
    

    有了更好的名字,更容易看出为什么你的原始代码不正确,因为科学家实际上并没有在alive_before/2alive_after/2 调用之间共享。

    另一个让您感到困惑的提示是,这个对查询的响应毫无意义:

    ?- alive_during(1628).
    X = boyle
    

    X 是从哪里来的?变量与查询中的值统一,它们不是从谓词体内到达的。

    更直接的解决方案是使用 Prolog 的内置 between/3 谓词:

    alive_during(Scientist, Year) :-
        scientist(Scientist, Birth, Death),
        between(Birth, Death, Year).
    

    这还有一个额外的好处,就是它实际上会为您生成解决方案:

    ?- alive_during(boyle, X).
    X = 1627 ;
    X = 1628 ;
    X = 1629 ;
    X = 1630 ;
    X = 1631 ;
    

    另一个解决方案没有这个属性。如果您确实具有此生成属性,则可以编写一些有趣的谓词,例如 contemporaries/2:

    contemporaries(S1, S2) :-
        alive_during(S1, Y),
        alive_during(S2, Y),
        dif(S1, S2).
    

    这会生成很多不感兴趣的解决方案副本,但您可以通过使用setof/3 来摆脱它们:

    ?- setof(X-Y, contemporaries(X, Y), Contemporaries).
    Contemporaries = [boyle-newton, newton-boyle].
    

    【讨论】:

    • 这确实有助于很好地解释它。谢谢。
    • @K.Hall 很高兴为您提供帮助,欢迎来到 Prolog!不要因此而气馁,我们都是从同一个地方开始的。
    猜你喜欢
    • 1970-01-01
    • 2011-04-04
    • 1970-01-01
    • 2011-02-06
    • 2020-01-04
    • 2020-11-23
    • 2015-03-16
    • 2012-04-15
    • 1970-01-01
    相关资源
    最近更新 更多