如何保留 Prolog 函数的第一个结果? [英] How to keep the first result of a function from Prolog?

查看:20
本文介绍了如何保留 Prolog 函数的第一个结果?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I need to write a customized function that will be called many times by other fixed functions. In this function, at the first called time, it will return the total number of lines of a file. The second called time of this function, forward, will return the number of lines in small sections of this file. My question is how I keep the first returned result(total number of lines of a file) and use it for the next called times of my function. I need to write or declare any thing only in this function(not in the caller). Something like this:

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

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

The problem is, every time myFunction is called, it receives different Input and returns different MyResult. But I would like to keep the first MyResult to use for next called times of myFunction. How can I do that? Thanks very much for your answer in advance.

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

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

The above is my function, there are other functions that will call myFunction by transfering value of V1, V2 to this function and get Result back.

推荐答案

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

What you need is some form of caching mechanism. That has to use some global resource somehow. The dynamic database is usually used for this purpose. Here is a very simplistic form of it. More sophisticated techniques in that area are known under the notion of tabling.

:- 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).当情况发生变化时不要忘记重置!

Usage: Start with reset. Then, wrap Goal as cached_call(Goal). Don't forget to reset when things change!

这里有一些解释:

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

reset/0 just removes all cached results.

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

eq/2 is equal up to renaming of variables, provided that the sets of variables of both arguments are disjoint.

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

cachedgoal_sol/2 is a dynamic predicate. It is used to store solutions (actually: answers) of a particular goal. To this purpose it keeps a copy of the actual goal in the first argument and the actual answer/solution in the second. Note that for one predicate there might be several, different queries. Say: member(X,[a,b,c]) and member(X,[X1,X2,X3]). These queries will be handled and cached independently of each other.

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

If a goal has to be cached anew, a copy of the term is created to have a "key" for the cache. Then, the goal is executed and each answer is stored - this is done exhaustively. This is particularly interesting for queries that have more than one answer.

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

Further the goal is protected with catch/3 catching all errors Pat. In this manner, all errors that happen to occur while executing the goal will cause a reset of the cache. This is particularly important for non-terminating queries: cached_call(length(L,N)) would otherwise leave a finite number of solutions in the cache - which would leave the cache in an inconsistent state...

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

In any case, the first clause always fails. So it is here only for the side effect of updating the cache.

第二个子句现在使用缓存.请注意,不可能将 XGoal = Goal 进一步向左",因为 eq/2 必须确保我们只使用相同查询的结果.

The second clause now uses the cache. Note that it is not possible to XGoal = Goal "further to the left", because eq/2 has to ensure that we are using only the results of the very same query.

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

As I said already: This is a very naive way of doing this, but at least it is simple and relatively robust.

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

As to your original program. You can now write:

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

每次您需要该值时.

这篇关于如何保留 Prolog 函数的第一个结果?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆