a minimal attempt: create a file named switch.pl
:- module(switch, []).
compile_caselist(X, [K:Clause], (X = K -> Clause)) :- !.
compile_caselist(X, [K:Clause|CaseList], ((X = K -> Clause);Translated)) :-
compile_caselist(X, CaseList, Translated).
:- multifile user:goal_expansion/2.
user:goal_expansion(F, G) :-
F = switch(X, CaseList),
compile_caselist(X, CaseList, G).
then use it like as usual: for instance, in a file switch_test.pl
:- use_module(switch).
test1(X) :-
X = a -> writeln(case1) ;
X = b -> writeln(case2) ;
X = c -> writeln(case3).
test2(X) :-
switch(X, [
a : writeln(case1),
b : writeln(case2),
c : writeln(case3)
]).
after compilation of switch_test.pl:
?- listing(test2).
test2(A) :-
( A=a
-> writeln(case1)
; A=b
-> writeln(case2)
; A=c
-> writeln(case3)
).
true.
edit due to multiple requests, here is a compilation schema to separate clauses:
:- module(switch, []).
:- multifile user:term_expansion/2.
user:term_expansion((H:-B), [(H:-T)|SWs]) :-
collect_switches(H,B,T,SWs),
SWs \= [],
debug(switch, 'compiled <~w>~nto <~w>~nwith <~w>', [H,T,SWs]).
collect_switches(H,(A0;A),(B0;B),SWs) :-
collect_switches(H,A0,B0,S0),
collect_switches(H,A,B,S),
append(S0,S,SWs).
collect_switches(H,(A0,A),(B0,B),[S|SWs]) :-
call_switch(H,A0,B0,S), !,
collect_switches(H,A,B,SWs).
collect_switches(H,(A0,A),(A0,B),SWs) :-
collect_switches(H,A,B,SWs).
collect_switches(H,A,B,[S]) :-
call_switch(H,A,B,S), !.
collect_switches(_,C,C,[]).
call_switch(H,switch(X,CL),call(G,X),CTs) :-
functor(H,F,A),
R is random(1000000),
format(atom(G), '~s_~d_~d', [F,A,R]),
maplist({G}/[K:C,(H:-C)]>>(H=..[G,K]),CL,CTs).
now the test script has been wrapped in a module, to ease further listing:
:- module(switch_test, [test1/1,test2/1]).
:- use_module(switch).
test1(X) :-
X = a -> writeln(case1) ;
X = b -> writeln(case2) ;
X = c -> writeln(case3).
test2(X) :-
switch(X, [
a : writeln(case1),
b : writeln(case2),
c : writeln(case3)
]).
and the result, after compiling switch_test.pl
:
?- switch_test:listing.
test1(A) :-
( A=a
-> writeln(case1)
; A=b
-> writeln(case2)
; A=c
-> writeln(case3)
).
test2(A) :-
call(test2_1_362716, A).
test2_1_362716(a) :-
writeln(case1).
test2_1_362716(b) :-
writeln(case2).
test2_1_362716(c) :-
writeln(case3).
to ease debugging:
?- debug(switch).
that outputs a message like this when compiling:
% [Thread pq] compiled <test2(_G121946)>
to <call(test2_1_362716,_G121946)>
with <[[(test2_1_362716(a):-writeln(case1)),(test2_1_362716(b):-writeln(case2)),(test2_1_362716(c):-writeln(case3))]]>
note: this sketch obviously is very likely to need more testing.
If you decide to benchmark the improvements (if any), please don't use IO statements (like writeln), since those would dominate anyway the execution timings.
term_expansion/2
andgoal_expansion/2
. To rewrite terms at compilation time. See SWI-Prolog'smaplist/2
inlibrary(apply_macros)
to see how one can compile such constructs to calls of auxiliary predicates. – Certainty