i keep expecting at some point that someone would’ve made a library to let you use asserta/z, clause/2/3, retract/all, etc., in a way that pretends the database supports attributed variables. one approach i’ve halfway done in the past is to actually keep the attribute goals in the body of the asserted clause, instead of trying to reconstruct attributes at query time.
for example, you might write:
tr(V, typing, t1), assertz_attvar((tv(V) :- hello(V))).
**
Behind the scenes, the library would use copy_term/3
to pull out any attribute goals from V
before storing the clause.** That way, what actually gets stored is:
tv(A) :- put_attr(A, typing, t1), hello(A).
so when you later call tv(X)
, the attribute gets restored automatically for that variable before the rest of your logic (hello(X)
) runs.
the library would provide alternate versions of all the standard dynamic predicates, each with _attvar
appended (for “attributed variable”). so you’d have:
-
assertz_attvar/1,2
-
asserta_attvar/1,2
-
assert_attvar/1,2
-
retract_attvar/1
-
retractall_attvar/1
-
clause_attvar/2
-
clause_attvar/3
maybe even a wrapper like with_attvars_in_assert_db/1
that could intercept such calls within a given scope, so you wouldn’t have to change every predicate in your codebase.
of course, the open question is whether restoring the attribute goals in this way (by prepending them to the body) will always match what users actually expect—especially regarding when attribute hooks get triggered during unification. it’s just one more thing that has to be answered: will the semantics really line up with what the library’s user wanted?
i’ve put together pieces of this a couple times, but i’ve never seen a polished, general-purpose library for it. seems like something the community should have by now!