1
votes

I have a function like this:

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.

There are other functions that call myFunction many times and get the Result back. However, I would like to get the first Result that myFunction is called first time and keep it to use for calls later(In this case, it is V1cover and V2cover). For example, first time, myFunction(4,4,A) is called. Then it returns A = 2. After that I would like to keep the value of V1cover(4) and V2cover(4) to use for next called times. How I can do that? I tried to apply a cached techonology like and apply it into 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).

but it doesn't work, when I try to run the second time myFunction(2,3,A) and trace the program, it actually stores solution of the first call but I couldn't get the first values of V1cover, V2cover since eq() in the second cached_call() fails. Is there a way to only get values of V1cover, V2cover without touching to V1,V2 since they are input? Thanks very much for your answer.

2
Those are not functions and you don't call them. You have predicates and goals you want to satisfy.Tudor Berariu

2 Answers

2
votes

Your code has some errors and it's a bit too complicated. I'll try to give you an answer that might be useful to others too.

Let's suppose we need a predicate to store information about the context in which a goal was first satisfied.

I'll use a simple example. Let's say we have a rule to find pairs of numbers between 1 and 4 that add to 6.

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

Trying to find all pairs that satisfy the above rule, one gets the following answer:

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

Now, let's return to your question. Let's suppose we need the first pair that satisfied the goal. We should modify the rule for predicate 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)).

The subgoal store_first(pair(X,Y)) succeeds every time, but asserts pair(X,Y) just the first time (if there is no other pair(_,_) in the dynamic memory). So, the answer you need might be something similar to this:

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)
        ).

Now, to get the stored information:

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

If you want only the first answer, simply write

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

using this definition.