0

我有这个阶乘谓词。

fact(0, 1).
fact(N, F) :- N > 0, 
        N1 is N-1,
        fact(N1, F1),
        F is F1 * N.

如何更改此谓词,以便每次发出查询时,将计算结果存储在数据库中?如果可用,新查询应使用存储的结果。

4

2 回答 2

1

您要查找的内容通常称为memoization,但在 Prolog 的上下文中称为表格。方便的是,有一个称为SWI Prolog 的表的库。

:- use_module(library(tabling)).
:- table fact/2.

fact(0, 1).
fact(N, F) :- N > 0,
              N1 is N-1,
              fact(N1, F1),
              F is F1 * N.

您可以通过trace在调用fact. 请注意,这两:-行称为指令并由编译器运行,因此在 repl 中运行它们将不起作用。

编辑

如果您不想使用表格库,可以使用asserta完成此操作。这将在数​​据库顶部插入一个事实,就好像您自己将它输入到文件中一样。

fact(0, 1).
fact(N, F) :-
              N > 0,
              N1 is N-1,
              fact(N1, F1),
              F is F1 * N,
              asserta(fact(N, F)).

Prolog 将首先看到新的谓词并将使用它而不是重新计算您的阶乘。再一次,您可以通过跟踪来检查这一点。

于 2017-03-02T04:53:34.723 回答
0

正如 jcolemang 所说,您想要的是表格/记忆。虽然确实有一些库是推荐的和高效的(不仅是时间方面,而且主要是性能方面)的做事方式,但您可能希望自己实现它是可以理解的。

可以使用 assert 在 prolog 数据库中添加动态事实,但您需要通过:-dynamic(fact)在允许您添加/删除事实的文件中声明它们。

但是,这样做会降低性能。另一种方法是有一个查找表/缓存,它将在调用之间保持不变。可以使用全局可变变量(哎呀!)来存储字典,这比使用动态事实更有效。与往常一样,最好尽量减少直接使用变量/副作用的代码 - 在您的阶乘示例中,您可以简单地使用一个包装谓词来获取字典并将其放回调用结束时,例如

factorial(N, F):-
get_global_dict(D),
real_factorial(N, F, D, DF),
store_global_dict(DF).
于 2017-03-03T19:43:43.487 回答