34
35:- module(neck,
36 [ neck/0,
37 neck/2,
38 necki/0,
39 necki/2,
40 necks/0,
41 necks/2,
42 neckis/0,
43 neckis/2
44 ]). 45
46:- use_module(library(lists)). 47:- use_module(library(pairs)). 48:- use_module(library(apply)). 49:- use_module(library(resolve_calln)). 50:- use_module(library(transpose)). 51:- use_module(library(choicepoints)). 52:- use_module(library(statistics)). 53:- use_module(library(ordsets)). 54:- use_module(library(solution_sequences)). 55:- use_module(library(checkct)). 56:- reexport(library(track_deps)). 57:- reexport(library(compound_expand)). 58:- init_expansors.
83neck.
84
85neck --> [].
94necki.
95
96necki --> [].
105necks.
106
107necks --> [].
115neckis.
116
117neckis --> [].
118
119current_seq_lit(Seq, Lit, Left, Right) :-
120 current_seq_lit(Seq, Lit, true, Left, true, Right).
121
122conj(T, C, C) :- T == true.
123conj(C, T, C) :- T == true.
124conj(A, B, (A, B)).
125
126current_seq_lit(S, _, _, _, _, _) :-
127 var(S),
128 !,
129 fail.
130current_seq_lit(S, S, L, L, R, R).
131current_seq_lit((H, T), S, L1, L, R1, R) :-
132 ( once(conj(T, R1, R2)),
133 current_seq_lit(H, S, L1, L, R2, R)
134 ; once(conj(L1, H, L2)),
135 current_seq_lit(T, S, L2, L, R1, R)
136 ).
137
138assign_value(A, V) -->
139 ( {var(A)}
140 ->{A=V}
141 ; [A-V]
142 ).
143
144neck_prefix('__aux_neck_').
145
146neck_needs_check(neck, true).
147neck_needs_check(necki, true).
148neck_needs_check(neck( _, _), true).
149neck_needs_check(necki( _, _), true).
150neck_needs_check(necks, fail).
151neck_needs_check(necks( _, _), fail).
152neck_needs_check(neckis, fail).
153neck_needs_check(neckis(_, _), fail).
154
155call_checks(Neck, File, Line, Call, HasCP) :-
156 neck_needs_check(Neck, Check),
157 has_choicepoints(do_call_checks(Check, File, Line, Call), nb_setarg(1, HasCP, no)).
158
159avl_testclause(AVL, F, Head, Body) :-
160 pairs_keys_values(AVL, ArgH, ArgB),
161 Head =.. [F|ArgH],
162 Body =.. [F|ArgB].
163
164sumarize_1(Key-LL, Key-[InfCurrent, InfOptimal]) :-
165 transpose(LL, [CL, OL]),
166 sum_list(CL, InfCurrent),
167 sum_list(OL, InfOptimal).
168
169variant_sha1_nat(Term, Hash) :-
170 copy_term_nat(Term, Tnat),
171 variant_sha1(Tnat, Hash).
172
173performance_issue(_-[InfCurrent, InfOptimal]) :- InfCurrent < InfOptimal.
174
175profile_expander(M, Head, AssignedL, Expanded, Issues) :-
176 findall(Key-[InfCurrent, InfOptimal],
177 ( F1 = '__aux_test_clause_evl',
178 TestH =.. [F1|AssignedL],
179 functor(TestH, F1, A),
180 F2 = '__aux_test_clause_seq',
181 functor(TestL, F2, A),
182 setup_call_cleanup(
183 assertz(M:TestH :- Expanded),
184 call_time(M:TestH, T1),
185 abolish(M:F1/A)),
186 foldl(assign_value, AssignedL, _, AVL, []),
187 avl_testclause(AVL, F2, TestB, TestL),
188 setup_call_cleanup(
189 assertz(M:TestB),
190 call_time(M:TestL, T2),
191 abolish(M:F2/A)),
192 variant_sha1_nat(M:Head, Key),
193 InfCurrent = T1.inferences,
194 InfOptimal = T2.inferences
195 ), InfCurrentU),
196 keysort(InfCurrentU, InfCurrentL),
197 group_pairs_by_key(InfCurrentL, InfCurrentG),
198 maplist(sumarize_1, InfCurrentG, InfCurrentS),
199 include(performance_issue, InfCurrentS, Issues).
200
201do_call_checks(true, File, Line, Call) :- call_checkct(Call, File, Line, []).
202do_call_checks(fail, _, _, Call) :- call(Call).
203
204link_neck_body(t(Pattern, NeckBody, NeckBody, Head), t(Pattern, Head)).
205
206term_expansion_hb(File, Line, M, Head, Neck, Static, Right, NeckHead, NeckBody, Pattern, ClauseL) :-
207 once(( current_seq_lit(Right, !, Left, SepBody),
208 \+ current_seq_lit(SepBody, !, _, _),
209 LRight = (Left, !)
210 211 ; LRight = true,
212 SepBody = Right
213 )),
214 term_variables(Head, HVars),
215 '$expand':mark_vars_non_fresh(HVars),
216 expand_goal(M:Static, Expanded),
217 freeze(NeckHead,
218 ( NeckHead = A:B
219 ->freeze(A, freeze(B, track_deps(File, Line, M, NeckHead, Expanded)))
220 ; track_deps(File, Line, M, NeckHead, Expanded)
221 )),
222 HasCP = hascp(yes),
223 term_variables(Head-Right, HNVarU),
224 term_variables(Expanded, ExVarU),
225 sort(HNVarU, HNVarL),
226 sort(ExVarU, ExVarL),
227 ord_intersection(ExVarL, HNVarL, AssignedL),
228 ( memberchk(Neck, [neck, neck(_, _), necks, necks(_, _)]),
229 Head \== '<declaration>',
230 nonvar(SepBody),
231 member(SepBody, [(_, _), (_;_), (_->_), \+ _]),
232 expand_goal(M:SepBody, M:ExpBody)
233 ->( ExpBody = true
234 ->expand_goal(M:LRight, M:NeckBody),
235 findall(t(Pattern, Head), call_checks(Neck, File, Line, Expanded, HasCP), ClausePIL),
236 RTHead = Head,
237 ClauseL1 = []
238 ; term_variables(t(Head, Expanded, LRight), VarHU),
239 '$expand':remove_var_attr(VarHU, '$var_info'),
240 sort(VarHU, VarHL),
241 term_variables(ExpBody, VarBU),
242 sort(VarBU, VarBL),
243 ord_intersection(VarHL, VarBL, ArgNB),
244 variant_sha1(ArgNB-ExpBody, Hash),
245 neck_prefix(NeckPrefix),
246 format(atom(FNB), '~w~w:~w', [NeckPrefix, M, Hash]),
247 SepHead =.. [FNB|ArgNB],
248 once(conj(LRight, SepHead, NeckBody1)),
249 findall(t(Pattern, NeckBody, NeckBody1, Head),
250 ( call_checks(Neck, File, Line, Expanded, HasCP)
251 ), ClausePIL1)
252 ->( ClausePIL1 = [t(Pattern, NeckBody, NeckBody1, Head)]
253 ->once(conj(LRight, ExpBody, NeckBody)),
254 ClausePIL = [t(Pattern, Head)],
255 RTHead = Head,
256 ClauseL1 = []
257 ; RTHead = SepHead,
258 maplist(link_neck_body, ClausePIL1, ClausePIL),
259 ( '$get_predicate_attribute'(M:SepHead, defined, 1),
260 '$get_predicate_attribute'(M:SepHead, number_of_clauses, _)
261 ->ClauseL1 = []
262 ; phrase(( findall((:- discontiguous IM:F/A),
263 distinct(IM:F/A,
264 ( member(t(_, H), ClausePIL),
265 H \== '<declaration>',
266 strip_module(M:H, IM, P),
267 functor(P, F, A)
268 ))),
269 ( { '$get_predicate_attribute'(M:SepHead, defined, 1),
270 '$get_predicate_attribute'(M:SepHead, number_of_clauses, _)
271 }
272 ->[]
273 ; [(SepHead :- ExpBody)]
274 )
275 ), ClauseL1)
276 )
277 )
278 )
279 ; expand_goal(M:Right, M:NeckBody),
280 findall(t(Pattern, Head), call_checks(Neck, File, Line, Expanded, HasCP), ClausePIL),
281 RTHead = Head,
282 ClauseL1 = []
283 ),
284 ( Head == '<declaration>'
285 ->true
286 ; HasCP = hascp(yes)
287 ->true
288 289 290 291 292 293 304 ; 305 306 307 308 309 profile_expander(M, Head, AssignedL, Expanded, Issues),
310 Issues \= []
311 ->maplist(warning_nocp(File, Line, M, Head), Issues),
312 fail
313 ; true
314 ),
315 phrase(( findall(Clause, member(t(Clause, _), ClausePIL)),
316 findall(Clause,
317 ( \+ memberchk(Neck, [necks, necks(_, _), neckis, neckis(_, _)]),
318 Head \== '<declaration>',
319 SepBody \= true,
320 distinct(Clause, st_body(Head, M, RTHead, ClausePIL, Clause))
321 ))
322 ), ClauseL, ClauseL1).
323
324term_expansion_hb(Head, Neck, Static, Right, NeckHead, NeckBody, Pattern, ClauseL) :-
325 source_location(File, Line),
326 '$current_source_module'(M),
327 term_expansion_hb(File, Line, M, Head, Neck, Static, Right, NeckHead, NeckBody, Pattern, ClauseL).
328
329st_body(Head, M, RTHead, ClausePIL, Clause) :-
330 member(t(_, Head), ClausePIL),
331 resolve_calln(RTHead, RTHeadN),
332 strip_module(M:RTHeadN, RTM, RTPred),
333 functor(RTPred, RTF, RTA),
334 member(Clause, [(:- discontiguous RTM:RTF/RTA) 335 336 ]).
337
338warning_nocp(File, Line, M, H, _-[InfCurrent, InfOptimal]) :-
339 print_message(
340 warning,
341 at_location(
342 file(File, Line, -1, _),
343 format("Ignored neck on ~w, since it could cause performance degradation (~w)",
344 [M:H, InfCurrent < InfOptimal]))).
345
346check_has_neck(Body, Neck, Static, Right) :-
347 once(( current_seq_lit(Body, Neck, Static, Right),
348 memberchk(Neck, [neck, neck(X, X), necki, necki(X, X),
349 necks, necks(X, X), neckis, neckis(X, X)])
350 )).
351
352term_expansion((Head :- Body), ClauseL) :-
353 check_has_neck(Body, Neck, Static, Right),
354 term_expansion_hb(Head, Neck, Static, Right, Head, NB, (Head :- NB), ClauseL).
355term_expansion((Head --> Body), ClauseL) :-
356 current_seq_lit(Body, Neck1, _, _),
357 memberchk(Neck1, [neck, necki, necks, neckis]),
358 ( var(Head)
359 ->dcg_translate_rule((call(Head) --> Body), _, (H1 :- B), _),
360 freeze(Head, resolve_calln(H1, H))
361 ; dcg_translate_rule((Head --> Body), _, (H :- B), _),
362 H1 = H
363 ),
364 check_has_neck(B, Neck, Static, Right),
365 term_expansion_hb(H1, Neck, Static, Right, H, NB, (H :- NB), ClauseL).
366term_expansion((:- Body), ClauseL) :-
367 check_has_neck(Body, Neck, Static, Right),
368 term_expansion_hb('<declaration>', Neck, Static, Right, '<declaration>', NB, (:- NB), ClauseL).
369
371goal_expansion(phrase(Body, L, T), Expanded) :-
372 nonvar(Body),
373 374 dcg_translate_rule(('$head$' --> Body, '$sink$'), _, ('$head$'(L, _) :- Expanded, '$sink$'(T, _)), _)
Neck, a Compile-Time Evaluator
Implements several predicates to establish that everything above them should be evaluated at compile time, be careful since such part can only contain predicates already defined. In case of non-determinism, several clauses would be generated. This is a practical way to generate automatic clauses with a proper instantiation of the head. If the code can not be expanded, it will succeed without side effects.
These predicates can also be used in declarations, although in that case, no warnings will be shown about run-time parts being executed, since declarations are executed at compile-time.
*/