I was looking for a way to manage side-effects but hopefully without using non-logical predicates like
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/2isn’t the fastest)
I’ll keep this gist updated in the future: Pure way for tracking state of variables in Prolog · GitHub