实现用户定义的算术函数
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/2
和 goal_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相同,这样最后就有提速了。
如何添加一个函数(例如 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/2
和 goal_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相同,这样最后就有提速了。