通过Prolog中的程序推理

时间:2016-04-02 13:26:13

标签: debugging prolog

我正在尝试Prolog考试的过去的纸质问题。我画了一棵树'因为我认为Prolog应该按照计划和某个目标行事。但是,Prolog的行为并不像我预期的那样,并且根据我认为它会返回“真实”的查询,它实际上返回了“假”。

这是我的计划:

sum(Term,N) :- Term = 0, N = 0.
sum(Term,N) :- Term = f(M,Subterm), number(M), sum(Subterm,N-M).

我的查询和搜索树如下(目标括号内并以粗体显示):

[sum(f(1,0),1)]

使用规则1,让Term = 0,N = 0,尝试统一 [1 = 0,1 = 0] 失败。

重做:使用规则2,让Term = f(1,0),N = 1 [f(1,0)= f(M,Subterm),数字(M),sum(Subterm,1 -1)]

统一,让M = 1,子项= 0 [数字(1),总和(0,0)]

使用规则1,这应该成功。然而(SWI)Prolog说' false'。

如果有人可以向我指出为什么我的推理存在缺陷(以及将来如何从中吸取教训),我将非常感激。

2 个答案:

答案 0 :(得分:4)

由于您的程序几乎是纯 1 ,所以您可以在不使用调试器的情况下以系统方式定位错误。我们的想法是通过逐个删除目标来概括您的计划。我提出了以下纯粹的概括,我通过"评论"像这样的目标:

:- op(950, fy, *).
*(_).

sum(Term,N) :-
   Term = 0,
   N = 0.
sum(Term,N) :-
   * Term = f(M,Subterm),
   * number(M),
   sum(Subterm,N-M).

?- sum(Term, N).
   Term = 0, N = 0
;  false.

此外,上述查询比您​​的查询更为通用。这是Prolog中非常有用的技术:我们不是考虑具体的解决方案 首先让Prolog为我们完成所有工作。

答案非常清楚:这种关系只有一种解决方案,即使这种关系现在已经推广了。

所以问题必须在剩下的可见部分中。实际上,它是-。为什么不写呢:

:- use_module(library(clpfd)).

sum(0, 0).
sum(Term, N0) :-
   Term = f(M, Subterm),
   N0 #= M+N1,
   sum(Subterm, N1).

我发现该程序更容易理解。如果我读了一个名字sum,我会立即寻找相应的+。当然,如果你坚持,你可以写N0-M #= N1代替。它将完全相同,除了这需要更多的思考。

您不需要阅读的小字

1)您的原始程序使用的number/1不是纯粹的。但是,由于删除问题仍然存在,这并没有损害我们的推理。

答案 1 :(得分:0)

为了更准确,第一条规则会尝试统一f(1,0) = 01 = 0,这当然会失败。

对规则2的分析也是不正确的。部分地,它是因为Prolog 评估内联的算术表达式。术语N-M只是一个术语('-'(N, M)的简称。除非M明确地通过{{1}进行评估,否则不会导致从M中减去is/2或算术比较(例如=:=/2=</2等)。

对规则2的分析如下。由于上述原因,步骤5是您的逻辑崩溃的地方。

  1. 致电sum(f(1,0), 1)会产生Term = f(1,0)N = 1
  2. 在规则2中,Term = f(M, Subterm)变为f(1,0) = f(M, Subterm),从而产生M = 1Subterm = 0
  3. number(N)变为number(1)并成功(因为1是数字)
  4. 来电sum(Subterm, N-M)变为sum(0, 1-1)
  5. Prolog将sum(0, 1-1)与规则1 sum(Term, N) :- Term = 0, N = 0.的头部匹配,但失败,因为1-1 = 0(与'-'(1, 1) = 0统一相同失败。
  6. Prolog将sum(0, 1-1)与规则2的头部匹配,并统一Term = 0N = 1-1(或N = '-'(1, 1))。
  7. Term = f(M, Subterm)变为0 = f(M, Subterm)失败,因为0无法与字词f(M, Subterm)匹配。
  8. 没有更多的规则要尝试,因此谓词调用失败。
  9. 这里的简单修复是使用新变量明确评估表达式的常见基本Prolog模式:

    sum(Term,N) :-
        Term = f(M,Subterm),
        number(M),
        R is N - M,
        sum(Subterm, R).
    

    你也可以通过统一条款的头部来整理代码。所以这些条款可以改写:

    sum(0, 0).
    sum(f(M, Subterm), N) :-
        number(N),
        R is N - M,
        sum(Subterm, R).
    

    <小时/> EDIT :我的回答旨在指导您完成现有逻辑。除了纠正有关表达评估的误解之外,我没有分析你的整体正确性的解决方案。