Из документов я решил, что вы должны использовать function_expansion / 3.Но я не могу заставить его работать, вместо этого goal_expansion может, но не очень привлекательно ... например, если вы сохраните следующие определения в файле bind.pl (просто дляскажем)
:- module(bind, [test/0]).
:- dynamic bind/2.
bind(a, 3).
bind(b, 4).
bind(c, 5).
% :- multifile user:goal_expansion/2.
user:goal_expansion(val(X), Y) :- bind(X, Y).
user:goal_expansion(X is Y, X is Z) :- expand_goal(Y, Z).
user:goal_expansion(X + Y, U + V) :- expand_goal(X, U), expand_goal(Y, V).
test :-
X is val(a) + val(b), writeln(X).
и обратитесь к нему, вы можете запустить свой тест:
?- test.
7
изменить
после предложения Пауло, вотрасширенное решение, которое должно работать для каждого двоичного выражения.
user:goal_expansion(X is Y, X is Z) :- expr_bind(Y, Z).
expr_bind(val(A), V) :- !, bind(A, V).
expr_bind(X, Y) :-
X =.. [F, L, R], % get operator F and Left,Right expressions
expr_bind(L, S), % bind Left expression
expr_bind(R, T), % bind Right expression
Y =.. [F, S, T]. % pack bound expressions back with same operator
expr_bind(X, X). % oops, I forgot... this clause allows numbers and variables
, определив user в качестве целевого модуля для goal_expansion, работает на CLI:
?- R is val(a)*val(b)-val(c).
R = 7.
edit
Теперь давайте обобщим некоторые другие арифметические операторы, используя тот же скелет, который expr_bind использует для двоичных выражений:
user:goal_expansion(X, Y) :-
X =.. [F,L,R], memberchk(F, [is, =<, <, =:=, >, >=]),
expr_bind(L, S),
expr_bind(R, T),
Y =.. [F, S, T].
и унарныйоператоры (я не могу вспомнить никого, кроме минуса, поэтому я показываю более простой способ, чем (= ..) / 2):
...
expr_bind(-X, -Y) :- expr_bind(X, Y).
expr_bind(X, X).
Теперь мы получаем
?- -val(a)*2 < val(b)-val(c).
true.