【问题标题】:How to store the first returned value of a function in prolog?如何在prolog中存储函数的第一个返回值?
【发布时间】:2014-06-07 08:13:10
【问题描述】:

我有这样的功能:

myFunction(V1, V2, Result) :-
  Result is V1/V1cover + V2/V2cover,
  write(Result).

myFunction(0,0,0).

keepValue(V1,V2,V1cover,V2cover) :-
  V1cover is V1,
  V2cover is V2.

还有其他函数多次调用 myFunction 并返回 Result。但是,我想获得第一次调用 myFunction 的第一个结果,并保留它以供以后调用(在这种情况下,它是 V1cover 和 V2cover)。例如,第一次调用 myFunction(4,4,A)。然后它返回 A = 2。之后我想保留 V1cover(4) 和 V2cover(4) 的值以用于下一次调用。我怎么能这样做?我尝试应用缓存技术并将其应用到 myFunction:

 :- dynamic(cachedGoal_sol/2).

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

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

 cached_call(Goal) :-
   \+ (cachedGoal_sol(First,_), eq(First, Goal)),
   copy_term(Goal, First),
   catch(
   ( Goal,
     assertz(cachedGoal_sol(First, Goal)),
     fail
   ),
   Pat,
   (reset, throw(Pat))).

 cached_call(Goal) :-
   cachedGoal_sol(First, Results),
   eq(First, Goal),
   Results = Goal.

 myFunction(V1, V2, Result) :-
  **cached_call(keepValue(V1,V2,V1cover,V2cover),**
  Result is V1/V1cover + V2/V2cover,
  write(Result).

但它不起作用,当我尝试第二次运行 myFunction(2,3,A) 并跟踪程序时,它实际上存储了第一次调用的解决方案,但我无法获得 V1cover 的第一个值, V2cover 因为第二个 cached_call() 中的 eq() 失败。有没有办法只获取 V1cover、V2cover 的值而不触及 V1、V2,因为它们是输入的?非常感谢您的回答。

【问题讨论】:

  • 那些不是函数,你不调用它们。您有想要满足的谓词和目标。

标签: prolog logic


【解决方案1】:

您的代码有一些错误,而且有点太复杂了。我会尽力给你一个可能对其他人也有用的答案。

假设我们需要一个谓词来存储有关首次满足目标的上下文的信息。

我将使用一个简单的示例。假设我们有一个规则来查找 1 到 4 之间的数对,它们相加为 6。

sum_to_six(X, Y) :- between(1, 4, X), between(1, 4, Y), X + Y =:= 6.

尝试找出所有满足上述规则的对,得到以下答案:

?- findall(pair(X,Y), sum_to_six(X, Y), All).
All = [pair(2, 4), pair(3, 3), pair(4, 2)].

现在,让我们回到您的问题。假设我们需要满足目标的第一对。我们应该修改谓词sum_to_six/2的规则。

sum_to_six(X, Y):-
        between(1, 4, X), between(1, 4, Y), X + Y =:= 6,
        store_first(pair(X,Y)).

子目标store_first(pair(X,Y))每次都成功,但只是第一次断言pair(X,Y)(如果动态内存中没有其他pair(_,_))。所以,你需要的答案可能是这样的:

store_first(Goal):-
        Goal =.. [Name | Args],  %% Name is the name of the predicate
        length(Args, N),         %% N represents its arity
        length(NVars, N),
        Test =.. [Name | NVars], %% Test is a goal like p(_, _, _, ...)
        (
         Test, !
        ;
         assertz(Goal)
        ).

现在,获取存储的信息:

?- retractall(pair(_,_)), findall(_, sum_to_six(_,_), _), pair(FirstX, FirstY).
FirstX = 2,
FirstY = 4.

【讨论】:

  • 嗨,Tudor,你能告诉我什么是测试吗?你是什​​么意思 p(,,...)?此外,NVars 在哪里,为什么需要将 length(Nvars,N) 放在 length(Args,N) 和 Test =.. 之间?非常感谢您的回答。
  • 所以,我希望Goal 必须是一阶结构p(arg1,arg2,...argn)。这是此实现的一个限制,但对您来说可能就足够了。那么Name 是p(谓词的名称),Args 是它的参数列表。我们只对寻找 p 的数量感兴趣,这就是将length(Args, N) 放在那里的目的。子目标length(NVars,N) 将通过将 NVar 与未绑定变量列表统一来满足。那么Test是一个与任何与Goal相似的事实相统一的目标。如果内存中不存在这样的事实,则断言 Goal,否则不断言。
  • 您可以任意次数满足sum_to_six(X,Y)。您将拥有第一对成功的XY。在 prolog 中试试这个:?- sum_to_six(2,4),然后是 sum_to_six(3,3) 和其他。每次你请求pair(FirstX, FirstY),你都会得到FirstX=2, FirstY=4
  • 要随时访问满足您目标的第一对 (X,Y),您只需放置一个子目标 pair(X, Y)
  • 带有retractall ... findalll ... pair(FirstX, FirstY) 的部分只是让目标sum_to_six(X,Y) 满足几次的例子,最后在内存中有一个事实pair(FirstX, FirstY) 对应于成功的第一对.
【解决方案2】:

如果你只想要第一个答案,只需写

..., cached_call(once(Goal)), ....

使用this definition

【讨论】:

    猜你喜欢
    • 2020-06-06
    • 2013-02-10
    • 2021-09-18
    • 2020-11-20
    • 2020-11-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多