所以我正在学习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
的问题,我添加了下半部分作为澄清。)
最好选择两个问题的解决方案,但只要解决一个就足够了。
答案 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来限制目标中某些变量的范围,而不必同时限制目标中每个统一的范围。