在Prolog中定义规则以避免算术错误是/ 2

时间:2016-04-08 12:10:04

标签: prolog

我正在尝试在Prolog中实现二叉树,我收到以下错误:

task unzipJar(type: Copy) {
   from zipTree('commons-collections-3.2.jar')
   into ("$buildDir/libs/commons-collection")
   include "**/*.class"
   exclude "**/Unmodifiable.class"
}

dependencies {
   compile files("$buildDir/libs/commons-collection") {
      builtBy "unzipJar"
   }
}

我知道发生此错误是因为未正确实例化了/ 2的RHS。 但我发现很难弄清楚如何在第二个tree_eval / 3中实例化我的变量z。

ERROR: is/2: Arithmetic: `z/0' is not a function

如何在此处为z分配值?

提前致谢。

1 个答案:

答案 0 :(得分:4)

通过z=Value,您实际上将变量Value与原子z统一起来。如果你的意思是z是变量,你必须把它写成大写字母Z,因为@vmg指出:

tree_eval(Value,tree(empty,Z,empty),Value):-
        Z = Value.

在这种情况下,考虑查询谓词时会发生什么是很有趣的:

   ?- tree_eval(V,tree(empty,3,empty),E).
E = 3 ? ;
E = V = 3 ? ;
no

第一个解决方案是由您的第一个规则产生的,其中第一个参数有一个匿名变量。第二个解决方案是由您的第二个规则生成的,其中您要求第一个和第三个参数相同。所以基本上你有两个派生路径,两个案例中的值为3。现在让我们看一下稍微大一点的树:

?- tree_eval(V,tree(tree(empty,2,empty),+,tree(empty,3,empty)),E).
E = 5 ? ;
E = 5,
V = 3 ? ;
E = 5,
V = 2 ? ;
no

第一个答案并不令人惊讶,因为树的评估确实为5,但接下来的两个解决方案呢?让我们来看看prolog如何实现这些解决方案:术语

tree(tree(empty,2,empty),+,tree(empty,3,empty))

仅与第三个规则匹配,因为子树不为空。因此,使用子树tree(empty,2,empty)调用tree_eval / 3并作为第一个解决方案产生:(_,tree(empty,2,empty),2)

然后使用第一个解决方案为子树tree(empty,3,empty)调用tree_eval / 3:(_,tree(empty,3,empty),3)

现在eval(2,3,+,Eval)会产生Eval=5。然而,第一个论点仍然是Value=_。因此,查询的第一个解决方案是:E=5

如果你要求其他答案prolog会尝试进一步解决第三个目标,确定没有,因此回溯到第二个目标:正确的子树,实际上你的第二个规则提供:(3,tree(empty,3,empty),3)eval(2,3,+,Eval)再次提供Eval=5,因此是查询的第二个解决方案:E=5, V=3

如果您仍然需要更多解决方案,prolog必须进一步回溯到第一个目标:并且您的第二个规则再次提交:(2,tree(empty,2,empty),2)。现在,您的第二个目标再次与第一个规则匹配:(_,tree(empty,3,empty),3),eval / 4再次传递Eval=5,因此查询的第三个解决方案是:E=5, V=2

再次回溯到目标2 prolog再次尝试第二个规则并失败,因为第一个参数不能同时为2和3。所以查询没有第四种解决方案。

但是,如果使用相同的树结构查询tree_eval / 3但是两个叶子都是2,那么通过上述推理,有4个解决方案并不令人惊讶:

   ?- tree_eval(V,tree(tree(empty,2,empty),+,tree(empty,2,empty)),E).
E = 4 ? ;
E = 4,
V = 2 ? ;
E = 4,
V = 2 ? ;
E = 4,
V = 2 ? ;
no

看看这些多种解决方案,很明显你的第三个论点是提供正确的解决方案,而你并不真正需要第一个论点。你也可以不用第二条规则。结合@mat建议的一些改进,你的谓词可能看起来像这样:

tree_evaluation(tree(empty,Num,empty),Num).
tree_evaluation(tree(L,Op,R),Val) :-
    tree_evaluation(L,LVal),
    tree_evaluation(R,RVal),
    evaluation(LVal,RVal,Op,Val).

evaluation(L,R,+,V) :-
    V is L + R.
evaluation(L,R,-,V) :-
    V is L - R.
evaluation(L,R,/,V) :-
    V is L / R.

这个版本产生了独特的答案:

    ?- tree_evaluation(tree(empty,3,empty),E).
E = 3 ? ;
no

     ?- tree_evaluation(tree(tree(empty,2,empty),+,tree(empty,3,empty)),E).
E = 5 ? ;
no