foreach中的Prolog算法

时间:2018-09-27 03:59:33

标签: math scope prolog

所以我正在学习Prolog。以下示例演示了我发现确实令人讨厌的一件事:

foreach(
  between(1,10,X),
  somePredicate(X,X+Y,Result)
).

这不起作用。我很清楚,这里没有对X + Y进行评估,而是必须这样做:

foreach(
  between(1,10,X),
  (
    XPlusY is X + Y,
    somePredicate(X, XPlusY, Result)
  )
).

除了,那也不起作用。据我所知,XPlusY的范围超出了foreach的范围,即XPlusY is 1 + Y, XPlusY is 2 + Y,等必须全部为true,并且没有XPlusY案件。因此,我必须执行以下操作:

innerCode(X, Result) :-
  XPlusY is X + Y,
  somePredicate(X, XPlusY, Result).
...

foreach(
  between(1,10,X),
  innerCode(X, Result)
).

这终于奏效了。 (至少,我认为是这样。我没有尝试过这个 exact 代码,但这是我之前从“不工作”到“工作”的路径。)很好,一切都很好,除了那个这是非常令人讨厌的。如果我有一种内联评估算术运算的方法,我可以将代码行减半,使其更具可读性,而不会创建一次性使用的谓词。

问题:是否可以在不声明新变量的情况下在线评估算术运算?

如果没有办法限制新变量的范围,那将是可以接受的(在某些情况下,对其他事物仍然有用)。例如,假设您可以在foreach内定义一个块,其中标记了从外部可见的变量,并且对该块的执行而言,该块中的其他任何变量都被认为是新变量。 (我意识到我的术语可能不正确,但希望可以理解这一点。)例如,类似以下内容:

foreach(
  between(1,10,X),
  (X, Result){
    XPlusY is X + Y,
    somePredicate(X, XPlusY, Result)
  }
).

可能的解决方案是,如果我们可以内联声明lambda并立即调用它。总结:

替代问题:是否有一种方法可以限制谓词中新变量的范围,同时保留对一个或多个现有变量执行持久统一的能力?

(为澄清有关forall的问题,我添加了下半部分作为澄清。)

最好选择两个问题的解决方案,但只要解决一个就足够了。

2 个答案:

答案 0 :(得分:2)

library(yall)允许您定义lambda表达式。例如

?- [library(lambda)].
true.

?- foreach(between(1,3,X),call(\Y^(Z is Y+1,writeln(Z)),X)).
2
3
4
true.

或者,library(lambda)提供了以下构造:

?- pack_install(lambda).

在SWI-Prolog中,库(yall)已自动加载,而要获取库(lambda),则应安装相关的软件包:

1, 4, 13, 40, 121, ...

答案 1 :(得分:0)

替代使用forall/2事实上的标准谓词:

forall(
  between(1,10,X),
  somePredicate(X,X+Y,Result)
).

foreach/2谓词通常以您描述的方式实现,而forall/2谓词的定义为:

% forall(@callable, @callable)

forall(Generate, Test) :-
    \+ (Generate, \+ Test).

请注意,使用否定表示对谓词的调用成功后将不返回任何绑定。

更新

Lambda库允许同时指定lambda全局变量(aka lambda free)和lambda局部变量(aka lambda参数)。使用Logtalk lambdas语法(也可以在library(yall)的SWI-Prolog中使用),例如,可以编写(重用Carlo的示例)

?- G = 2, foreach(between(1,3,X),call({G}/[Y]>>(Z is Y+G,writeln(Z)),X)).
3
4
5
G = 2.

?- G = 4, foreach(between(1,3,X),call({G}/[Y]>>(Z is Y+G,writeln(Z)),X)).
5
6
7
G = 4.

因此,可以使用lambda来限制目标中某些变量的范围,而不必同时限制目标中每个统一的范围。