I was looking for a way to manage side-effects but hopefully without using non-logical predicates like assert
and retractall
. Basically, I’m trying to mimic this Python code:
x = 3
x = 'something-else'
x = 5
I’ve came up with this code for Prolog:
% get_value(Value, History)
% History tracks values set for variable
% uses an arbitrary term t/1 just to allow adding a regular logical variable to the List
get_value(Val, List) :-
nonvar(List), % just so that fails when nothing added yet.
nextto(t(Val), Var, List),
var(Var),
!.
available_spot(X, History) :-
once((member(X, History), var(X))).
add_value(Val, History) :-
available_spot(X, History),
t(Val) = X.
Some example outputs:
% add one value for variable and read it back:
?- add_value(abc, History), get_value(Current, History).
History = [t(abc), _5110|_5112],
Current = abc.
% works for multiple "re-assignments" to same variable:
?- add_value(3, History), get_value(FirstWas, History), add_value('my-symbol', History), get_value(SecondWas, History), add_value(2, History), add_value(AVar, History), get_value(LatestIs, History), LatestIs = xyz.
History = [t(3), t('my-symbol'), t(2), t(xyz), _1946|_1948],
FirstWas = 3,
SecondWas = 'my-symbol',
AVar = LatestIs, LatestIs = xyz.
% fails when no value was previously set (as intended)
?- get_value(X, History).
false.
So, it seems to be doing the trick! We can even go back to previous states if needed. But I don’t recall seeing anything like this from experts! So I’d like your advice:
- Does this idea make any sense?
- How do you manage state if you absolutely want to maintain logical purity?
- How would you improve this? (e.g maybe
member/2
isn’t the fastest)
I’ll keep this gist updated in the future: Pure way for tracking state of variables in Prolog · GitHub