如何修复这种递归乘法? [英] How to fix this recursive multiplication?

查看:0
本文介绍了如何修复这种递归乘法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是逻辑编程和PROLOG的新手。以下PROLOG程序定义了一个谓词mul/3,用于将第一个参数与第二个参数相乘,从而产生第三个参数,该谓词的基础是等效于(x−1)*y+y=z

mul(0, _, 0).
mul(X, Y, Z) :-
  ground(X),
  succ(U, X),
  add(V, Y, Z),
  mul(U, Y, V).
mul(X, Y, Z) :-
  var(X),
  add(V, Y, Z),
  mul(U, Y, V),
  succ(U, X).

add(0, Y, Y).
add(X, Y, Z) :-
  ground(X),
  ground(Z),
  succ(U, X),
  succ(V, Z),
  add(U, Y, V).
add(X, Y, Z) :-
  ground(X),
  var(Z),
  succ(U, X),
  add(U, Y, V),
  succ(V, Z).
add(X, Y, Z) :-
  ground(Z),
  var(X),
  succ(V, Z),
  add(U, Y, V),
  succ(U, X).

但此参数模式下的查询会耗尽资源:

?- mul(X, Y, 2).
   X = 1, Y = 2
;  X = 2, Y = 1
;
Stack limit (0.2Gb) exceeded
  Stack sizes: local: 0.2Gb, global: 20.8Mb, trail: 10.4Mb
  Stack depth: 452,739, last-call: 0%, Choice points: 452,716
  In:
    [452,739] add(_1326, 0, 0)
    [452,738] add(_1354, 0, 1)
    [452,737] add(_1382, 0, 2)
    [452,736] mul(_1410, 0, 2)
    [452,735] mul(_1438, 0, 2)

如何修复此递归乘法?

推荐答案

该程序工作正常,因为它提供了两个解决方案:X = 1, Y = 2X = 2, Y = 1。然后,它会无限搜索其他解决方案。

此规则有问题:

mul(X, Y, Z) :-
  var(X),
  add(V, Y, Z),
  mul(U, Y, V),
  succ(U, X).

heremul(U, Y, V)递归的方式是第一个参数不是基础的,但前面的规则假定它是基础的(当V不是零时)。只需交换前两个参数即可解决问题。

但仍不尽如人意,请考虑

?- mul(2, 3, X).
   false.

这里的问题在前面的规则中:

mul(X, Y, Z) :-
  ground(X),
  succ(U, X),
  add(V, Y, Z),
  mul(U, Y, V).

add(V, Y, Z)的调用变为add(V, 3, Z),未定义。将其与下一个mul互换可解决此问题:

mul(X, Y, Z) :-
  ground(X),
  succ(U, X),
  mul(U, Y, V),
  add(V, Y, Z).

那么现在可以了吗?不完全是,例如

?- mul(X, 3, 6).
   false.

尝试使用

?- trace, mul(X,3,6).

并找出问题所在。

-编辑-

好的,让我们从头开始尝试。

为简化起见,首先看看前两个参数不是变量的情况:

% add1(+X, +Y, ?Z) [semidet]
add1(0, Y, Y) :-
  !.
add1(X, Y, Z) :-
  succ(X1, X),
  add1(X1, Y, Z1),
  succ(Z1, Z).

% mul1(+X, +Y, ?Z) [semidet]
mul1(0, _, 0) :-
  !.
mul1(X, Y, Z) :-
  succ(X1, X),
  mul1(X1, Y, Z1),
  add1(Z1, Y, Z).

然后是另一种情况,当总和/乘积已知时:

% add2(?X, ?Y, +Z) [nondet]
add2(0, Y, Y).
add2(X, Y, Z) :-
  succ(Z1, Z),
  add2(X1, Y, Z1),
  succ(X1, X).

% mul2(?X, ?Y, +Z) [nondet]
mul2(X, Y, 0) :-
  !,
  (X = 0; Y = 0).
mul2(X, Y, Z) :-
  nonvar(Y),
  !,
  succ(Y1, Y),
  add2(Z1, X, Z),
  mul2(X, Y1, Z1).
mul2(X, Y, Z) :-
  add2(Z1, Y, Z),
  mul2(X1, Y, Z1),
  succ(X1, X).
请注意,当mul2中的第三个规则递归时,它的第二个参数将是已知的,并由第二个规则使用。这与您最初编写的内容非常相似。

最后,您可以创建一个规则来选择您需要的规则:

add(X, Y, Z) :-
  nonvar(Z) -> add2(X, Y, Z); add1(X, Y, Z).

mul(X, Y, Z) :-
  nonvar(Z) -> mul2(X, Y, Z); mul1(X, Y, Z).

(当然,您可以使用var(X)等来统一这些规则,但我认为这样会清楚得多。)

这篇关于如何修复这种递归乘法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆