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.