我正在尝试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'。
如果有人可以向我指出为什么我的推理存在缺陷(以及将来如何从中吸取教训),我将非常感激。
答案 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) = 0
和1 = 0
,这当然会失败。
对规则2的分析也是不正确的。部分地,它是因为Prolog 不评估内联的算术表达式。术语N-M
只是一个术语('-'(N, M)
的简称。除非M
明确地通过{{1}进行评估,否则不会导致从M
中减去is/2
或算术比较(例如=:=/2
,=</2
等)。
对规则2的分析如下。由于上述原因,步骤5是您的逻辑崩溃的地方。
sum(f(1,0), 1)
会产生Term = f(1,0)
和N = 1
。Term = f(M, Subterm)
变为f(1,0) = f(M, Subterm)
,从而产生M = 1
和Subterm = 0
。number(N)
变为number(1)
并成功(因为1是数字)sum(Subterm, N-M)
变为sum(0, 1-1)
。sum(0, 1-1)
与规则1 sum(Term, N) :- Term = 0, N = 0.
的头部匹配,但失败,因为1-1 = 0
(与'-'(1, 1) = 0
统一相同失败。sum(0, 1-1)
与规则2的头部匹配,并统一Term = 0
和N = 1-1
(或N = '-'(1, 1)
)。Term = f(M, Subterm)
变为0 = f(M, Subterm)
失败,因为0
无法与字词f(M, Subterm)
匹配。这里的简单修复是使用新变量明确评估表达式的常见基本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 :我的回答旨在指导您完成现有逻辑。除了纠正有关表达评估的误解之外,我没有分析你的整体正确性的解决方案。