【问题标题】:How to keep the first result of a function from Prolog?如何保留 Prolog 函数的第一个结果?
【发布时间】:2014-07-25 07:23:08
【问题描述】:

我需要编写一个自定义函数,该函数将被其他固定函数多次调用。在这个函数中,在第一次调用时,它会返回一个文件的总行数。此函数的第二次调用时间 forward 将返回此文件小部分中的行数。我的问题是如何保留第一个返回的结果(文件的总行数)并将其用于函数的下一个调用时间。我只需要在这个函数中(而不是在调用者中)编写或声明任何东西。像这样的:

myFunction(Input, MyResult, FirstResult) :-
   calculateInputFunction(Input, Result),
   !,
   MyResult is Result,
   ... .

问题是,每次调用 myFunction 时,它接收到不同的 Input 并返回不同的 MyResult。但我想保留第一个 MyResult 用于 myFunction 的下一个调用时间。我怎样才能做到这一点?非常感谢您提前回答。

myFunction([V1,V2], Result) :-
  reset,
  cached_all(a(V1,V2)),
  use V1, V2 to calculate Result, 
  ...
  reset,
  finishedCode. 

以上是我的函数,还有其他函数会调用myFunction,将V1、V2的值传递给这个函数并取回Result。

【问题讨论】:

  • 其实我只是想把第一个结果存到这个参数里,下次用。
  • 实际上,如果我可以声明一个全局变量并将第一个结果存储到这个变量中,并下次使用它,这可能是一个解决方案,但是,我认为使用全局变量不是好主意。

标签: caching prolog logic memoization


【解决方案1】:

您需要的是某种形式的缓存机制。那必须以某种方式使用一些全球资源。动态数据库通常用于此 目的。这是它的一个非常简单的形式。该领域中更复杂的技术以表格的概念而闻名。

:- dynamic(cachedgoal_sol/2).

reset :-
   retractall(cachedgoal_sol(_,_)).


eq(A, B) :-
   subsumes_term(A, B),
   subsumes_term(B, A).

cached_call(Goal) :-
   \+ ( cachedgoal_sol(Skel,_), eq(Skel, Goal) ),  % No fitting Goal was cached
   copy_term(Goal, Skel),
      catch(
        (  Goal,
           assertz(cachedgoal_sol(Skel,Goal)),
           fail
        ),
        Pat,
        (reset, throw(Pat))).
cached_call(Goal) :-
   cachedgoal_sol(Skel,XGoal),
    eq(Skel, Goal),
    XGoal = Goal.

用法:以reset. 开头,然后将Goal 包装为cached_call(Goal)。当情况发生变化时不要忘记重置!

这里有一些解释:

reset/0 只是删除所有缓存的结果。

eq/2 等于重命名变量,前提是两个参数的变量集不相交。

cachedgoal_sol/2 是一个动态谓词。它用于存储特定目标的解决方案(实际上是:答案)。为此,它在第一个参数中保留实际目标的副本,在第二个参数中保留实际答案/解决方案。请注意,对于一个谓词,可能有多个不同的查询。说:member(X,[a,b,c]) 和 member(X,[X1,X2,X3])。这些查询将彼此独立地处理和缓存。

如果必须重新缓存目标,则会创建术语的副本以具有缓存的“键”。然后,执行目标并存储每个答案 - 这是彻底完成的。这对于有多个答案的查询特别有趣。

进一步的目标是通过catch/3 捕获所有错误Pat 来保护。这样,在执行目标时发生的所有错误都会导致缓存的reset。这对于非终止查询尤为重要:cached_call(length(L,N)) 否则会在缓存中留下有限数量的解决方案 - 这会使缓存处于不一致状态...

无论如何,第一个子句总是失败。所以这里只是为了更新缓存的副作用。

第二个子句现在使用缓存。请注意,XGoal = Goal“向左更远”是不可能的,因为eq/2 必须确保我们只使用相同查询的结果。

正如我已经说过的:这是一种非常幼稚的做法,但至少它简单且相对稳健。


至于您的原始程序。你现在可以写:

..., cached_call(calculateInputFunction(Input, Result)), ...

每次您需要该值时。

【讨论】:

  • 您好假,非常感谢您的回答。谓词“cached_call”存储谓词“cachedgoal_sol”(在本例中为myFunction)中的目标(在我的情况下为第一个结果),不是吗?首先,“cached_call”检查目标是否已经在数据库中(如果是,则失败)。 Skel 是存储目标的临时变量。在这种情况下,Pat 是什么,我知道这是一个例外,但这意味着什么?你能帮我澄清更多关于 eq(A,B)、第二个“cached_call”等谓词的信息吗?抱歉,我是 Prolog 新手,所以有点难以理解您的代码。
  • 我更新了我的问题以显示我的一般代码。非常感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-11
  • 2012-05-08
  • 2016-02-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多