You can simulate historized variables as follows:
get_current_value([X|L], Y) :- var(L), !, X = Y.
get_current_value([_|L], X) :- get_current_value(L, X).
set_new_value(L, X) :- var(L), !, L = [X|_].
set_new_value([_|L], X) :- set_new_value(L, X).
get_previous_value([X,_|L], Y) :- var(L), !, X = Y.
get_previous_value([_|L], X) :- get_previous_value(L, X).
Works like a charm:
?- set_new_value(X,3), get_current_value(X,Y).
X = [3|_],
Y = 3.
?- set_new_value(X,3), set_new_value(X,4),
get_current_value(X,Y), get_previous_value(X,Z).
X = [3, 4|_],
Y = 4,
Z = 3.
?- set_new_value(X,3),
(set_new_value(X,4), get_current_value(X,Y); get_current_value(X,Y)).
X = [3, 4|_],
Y = 4 ;
X = [3|_],
Y = 3.
Not extremly efficient, but the gist of how many things can be implemented under the hood, like backtrackable global variables or updatable attributed variables, and were implemented in early Prolog systems. Your Prolog system might do it more efficiently for you.
Edit 30.11.2021:
Another approach would be Picat canonical rewriting, at least I imagine access to previous value might be easy. Going more back in the past, accessing yesterday yesterdays values on the other hand possibly needs a log as in the above.
Such a log puts pressure on garbage collection, for example when an old value isn’t needed, but nevertheless kept and not reclaimed in deterministic code. Your Prolog system might have some special garbage collection for attributed variables, although this is often not really needed,
since backtracking search anyway quickly rolls back the log.