I was writing some code for a game. It handles geometry, so there’s lots of numeric constants. It was fairly obvious this was the road to hell.
Not wanting to dig constants out of a fact, I decided to use $cell_width type constants, so quickly banged this out.
:- module(symbolic_constant,
[
sym/2
]).
:- dynamic symbolic_constant/2.
sym(Name, Val) :-
asserta(symbolic_constant(Name, Val)).
expand_constants(In, In) :-
var(In),
!.
expand_constants($In, Out) :-
symbolic_constant(In, Out).
expand_constants($In, _Out) :-
\+ symbolic_constant(In, _),
throw(format('no such constant'-[In])).
expand_constants(In, In) :-
atomic(In).
expand_constants(In, Out) :-
is_dict(In),
dict_pairs(In, Tag, Pairs),
maplist(expand_pair, Pairs, PairsOut),
dict_pairs(Out, Tag, PairsOut),
!.
expand_constants(In, Out) :-
compound(In),
In =.. InList,
maplist(expand_constants, InList, OutList),
Out =.. OutList.
expand_constants(In, Out) :-
is_list(In),
maplist(expand_constants, In, Out).
expand_pair(K-V, KO-VO) :-
expand_constants(K, KO),
expand_constants(V, VO).
user:term_expansion(In, Out) :-
expand_constants(In, Out).
very dissatisfied. Is there a more robust way to do this, preferably a system predicate?
Ideally there would be some general map_term that takes each sub_term and applies some transform to it. I can trivially convert the above to such a thing, but I’m wondering why there isn’t a library predicate that does this. Am I missing it? I end up doing this about every 6 months.