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

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

问题描述

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

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. 

以上是我的函数,还有其他函数会通过将V1,V2的值传输到该函数并返回Result来调用myFunction.

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天全站免登陆