34
35:- module(arithmetic,
36 [ arithmetic_function/1, 37 arithmetic_expression_value/2 38 ]). 39:- use_module(library(error)). 40:- use_module(library(lists)). 41:- set_prolog_flag(generate_debug_info, false).
53:- meta_predicate
54 arithmetic_function(:),
55 arithmetic_expression_value(:, -). 56:- multifile
57 evaluable/2.
68arithmetic_function(Term) :-
69 throw(error(context_error(nodirective, arithmetic_function(Term)), _)).
70
71arith_decl_clauses(NameArity,
72 [(:- public(PI)),
73 arithmetic:evaluable(Term, Q)
74 ]) :-
75 prolog_load_context(module, M),
76 strip_module(M:NameArity, Q, Spec),
77 ( Q == M
78 -> PI = Name/ImplArity
79 ; PI = Q:Name/ImplArity
80 ),
81 ( Spec = Name/Arity
82 -> functor(Term, Name, Arity),
83 ImplArity is Arity+1
84 ; type_error(predicate_indicator, Term)
85 ).
92eval_clause(Term, (eval(Gen, M, Result) :- Body)) :-
93 functor(Term, Name, Arity),
94 functor(Gen, Name, Arity),
95 Gen =.. [_|Args],
96 eval_args(Args, PlainArgs, M, Goals, [Result is NewTerm]),
97 NewTerm =.. [Name|PlainArgs],
98 list_conj(Goals, Body).
99
100eval_args([], [], _, Goals, Goals).
101eval_args([E0|T0], [A0|T], M, [eval(E0, M, A0)|GT], RT) :-
102 eval_args(T0, T, M, GT, RT).
103
104list_conj([One], One) :- !.
105list_conj([H|T0], (H,T)) :-
106 list_conj(T0, T).
107
108eval_clause(Clause) :-
109 current_arithmetic_function(Term),
110 eval_clause(Term, Clause).
111
112term_expansion(eval('$builtin', _, _), Clauses) :-
113 findall(Clause, eval_clause(Clause), Clauses).
121arithmetic_expression_value(M:Expression, Result) :-
122 eval(Expression, M, Result).
123
124eval(Number, _, Result) :-
125 number(Number),
126 !,
127 Result = Number.
128eval(Term, M, Result) :-
129 evaluable(Term, M2),
130 visible(M, M2),
131 !,
132 call(M2:Term, Result).
133eval('$builtin', _, _).
134
135
136visible(M, M) :- !.
137visible(M, Super) :-
138 import_module(M, Parent),
139 visible(Parent, Super).
140
141
142 145
146math_goal_expansion(A is Expr, Goal) :-
147 expand_function(Expr, Native, Pre),
148 tidy((Pre, A is Native), Goal).
149math_goal_expansion(ExprA =:= ExprB, Goal) :-
150 expand_function(ExprA, NativeA, PreA),
151 expand_function(ExprB, NativeB, PreB),
152 tidy((PreA, PreB, NativeA =:= NativeB), Goal).
153math_goal_expansion(ExprA =\= ExprB, Goal) :-
154 expand_function(ExprA, NativeA, PreA),
155 expand_function(ExprB, NativeB, PreB),
156 tidy((PreA, PreB, NativeA =\= NativeB), Goal).
157math_goal_expansion(ExprA > ExprB, Goal) :-
158 expand_function(ExprA, NativeA, PreA),
159 expand_function(ExprB, NativeB, PreB),
160 tidy((PreA, PreB, NativeA > NativeB), Goal).
161math_goal_expansion(ExprA < ExprB, Goal) :-
162 expand_function(ExprA, NativeA, PreA),
163 expand_function(ExprB, NativeB, PreB),
164 tidy((PreA, PreB, NativeA < NativeB), Goal).
165math_goal_expansion(ExprA >= ExprB, Goal) :-
166 expand_function(ExprA, NativeA, PreA),
167 expand_function(ExprB, NativeB, PreB),
168 tidy((PreA, PreB, NativeA >= NativeB), Goal).
169math_goal_expansion(ExprA =< ExprB, Goal) :-
170 expand_function(ExprA, NativeA, PreA),
171 expand_function(ExprB, NativeB, PreB),
172 tidy((PreA, PreB, NativeA =< NativeB), Goal).
173
174expand_function(Expression, NativeExpression, Goal) :-
175 do_expand_function(Expression, NativeExpression, Goal0),
176 tidy(Goal0, Goal).
177
178do_expand_function(X, X, true) :-
179 evaluable(X),
180 !.
181do_expand_function(Function, Result, ArgCode) :-
182 current_arithmetic_function(Function),
183 !,
184 Function =.. [Name|Args],
185 expand_function_arguments(Args, ArgResults, ArgCode),
186 Result =.. [Name|ArgResults].
187do_expand_function(Function, Result, (ArgCode, Pred)) :-
188 prolog_load_context(module, M),
189 evaluable(Function, M2),
190 visible(M, M2),
191 !,
192 Function =.. [Name|Args],
193 expand_predicate_arguments(Args, ArgResults, ArgCode),
194 append(ArgResults, [Result], PredArgs),
195 Pred =.. [Name|PredArgs].
196do_expand_function(Function, _, _) :-
197 type_error(evaluable, Function).
198
199
200expand_function_arguments([], [], true).
201expand_function_arguments([H0|T0], [H|T], (A,B)) :-
202 do_expand_function(H0, H, A),
203 expand_function_arguments(T0, T, B).
204
205expand_predicate_arguments([], [], true).
206expand_predicate_arguments([H0|T0], [H|T], (A,B)) :-
207 do_expand_function(H0, H1, A0),
208 ( callable(H1),
209 current_arithmetic_function(H1)
210 -> A = (A0, H is H1)
211 ; A = A0,
212 H = H1
213 ),
214 expand_predicate_arguments(T0, T, B).
220evaluable(F) :-
221 var(F),
222 !.
223evaluable(F) :-
224 number(F),
225 !.
226evaluable([_Code]) :- !.
227evaluable(Func) :- 228 functor(Func, ., 2),
229 !.
230evaluable(F) :-
231 string(F),
232 !,
233 string_length(F, 1).
234evaluable(F) :-
235 current_arithmetic_function(F),
236 ( compound(F)
237 -> forall(arg(_,F,A), evaluable(A))
238 ; true
239 ).
245tidy(A, A) :-
246 var(A),
247 !.
248tidy(((A,B),C), R) :-
249 !,
250 tidy((A,B,C), R).
251tidy((true,A), R) :-
252 !,
253 tidy(A, R).
254tidy((A,true), R) :-
255 !,
256 tidy(A, R).
257tidy((A, X is Y), R) :-
258 var(X), var(Y),
259 !,
260 tidy(A, R),
261 X = Y.
262tidy((A,B), (TA,TB)) :-
263 !,
264 tidy(A, TA),
265 tidy(B, TB).
266tidy(A, A).
267
268
269 272
273:- multifile
274 system:term_expansion/2,
275 system:goal_expansion/2. 276
277system:term_expansion((:- arithmetic_function(Term)), Clauses) :-
278 arith_decl_clauses(Term, Clauses).
279
280system:goal_expansion(Math, MathGoal) :-
281 math_goal_expansion(Math, MathGoal)
Extensible arithmetic
This module provides a portable partial replacement of SWI-Prolog's user-defined arithmetic (evaluable) functions. It defines the compatibility directive arithmetic_function/1 and support for both runtime and compile-time evaluation of expressions that are a mixture between Prolog predicates used as functions and built-in evaluable terms. */