实现用户定义的算术函数

Implementing user-defined arithmetic functions

如何添加一个函数(例如 hammingweight)并在出现在右侧的表达式中使用它是一些 (is)/2 目标?

goal_expansion 或 term_expansion 之类的东西对这里有帮助吗?

我承认这不是一个很大的特性,但它可以提高我的一些 Prolog 程序的可读性。

编写自定义 (is)/2 谓词(实现自定义表达式求值器)是可行的,但我希望保持较低的运行时开销,因为我不想为此牺牲运行时开销的可读性案例.

ISO Prolog中没有这样的规定,既不扩展(is)/2也不依赖目标扩展。并且,查看一些实现为此目的提供的各种特定于实现的功能,没有普遍同意的方法来做到这一点。因此,实施您自己的 (my_is)/2 似乎是最好的方法。

另请注意,这不仅会影响 (is)/2,还会影响所有其他使用可评估仿函数的内置函数。特别是,所有算术比较内置函数(8.7 算术比较)(参见 this overview)都会受到影响。

您可以使用 Logtalk 的术语扩展机制,它是可移植的并且可以与它的十二个支持的 Prolog 编译器 (*) 一起使用。 Logtalk编译加载加载谓词接受Prolog文件,会输出对应的Prolog展开文件。例如,假设您要扩展的文件名为 source.pl 并且您的 term_expansion/2goal_expansion/2 谓词定义位于名为 expansions.pl 的文件中,您可以执行类似:

% first, load the expansion hooks:
| ?- [expansions].
...

% second, expand a file using those hooks:
| ?- logtalk_compile(source, [hook(user)]).
...

您将获得扩展文件,该文件将(默认情况下)命名为 source_pl.pl(在一个目录中,该目录将取决于 scratch_directory Logtalk 标志的值)。如果扩展包含在 Prolog 模块中,请在模块名称上方使用而不是 user。如果 source.pl 文件包含模块而不是纯 Prolog 代码,则需要为 term_expansion/2 谓词定义一些子句以避免 Logtalk 将模块编译为对象。但是在您不使用模块的更简单的情况下,上面的两个查询就足够了。

Logtalk 的术语扩展机制的一个可能有用的功能是,您可以通过使用 {}/1 控制结构将术语或目标包装起来,将其标记为不扩展或进一步扩展。

(*) 请注意,术语扩展机制不是标准的,并非所有 Prolog 实现都提供,并且实现之间存在显着差异。

我头脑简单(~20 LOC)的语法糖 lifter,它基于 goal_expansion。

带起重器,子句

longer(A,B) :-
    length(A,º) > length(B,º).

扩展为

longer(A, B) :-
    length(A, C),
    length(B, D),
    C > D.

许多 Prolog 系统不允许用户定义可评估谓词。 有时问题是可评估的谓词存在于 另一个命名空间。有时 Prolog 系统在用宿主语言进行算术计算时会回避跳回 Prolog 执行。

一些 Prolog 系统仍然具有用户定义的可评估谓词,例如 ECLiPSe Prolog 和 Jekejeke Prolog。在 Jekejeke Prolog 中,开销是两倍。令我惊讶的是新的 Dogelog 运行时用户可定义可评估 谓词显示优势:

/* Dogelog Runtime 0.9.5 */
fact(0, 1) :- !.
fact(N, X) :- M is N-1, fact(M, Y), X is Y*N.

fact2(0, 1) :- !.
fact2(N, X) :- X is fact2(N-1)*N.

for(_).
for(N) :- N > 1, M is N - 1, for(M).

% ?- time((for(1000), fact(1000, _), fail; true)).
% % Wall 1595 ms, trim 0 ms

% ?- time((for(1000), _ is fact2(1000), fail; true)).
% % Wall 1394 ms, trim 0 ms

我将轻微的速度优势归因于 fact2/2 中更简洁的表述。该公式使用较少的 Prolog 逻辑变量。并且用户定义的可评估谓词能够 (is)/2 在内部也没有 Prolog 逻辑变量,发生的宿主语言赋值不分配

一个Prolog逻辑变量或trail相同,这样最后就有提速了。