un tentativo minimo: creare un file denominato 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).
poi usarlo come al solito: ad esempio, in un 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)
]).
dopo la compilazione di switch_test. pl:
?- listing(test2).
test2(A) :-
( A=a
-> writeln(case1)
; A=b
-> writeln(case2)
; A=c
-> writeln(case3)
).
true.
modifica a causa di req multipla li ospiti, ecco uno schema di compilazione per separare clausole:
:- 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).
ora lo script di test è stato avvolto in un modulo, per facilitare ulteriormente lista:
:- 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)
]).
e il risultato, dopo la compilazione 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).
per facilitare il debug:
?- debug(switch).
che emette un messaggio come questo durante la compilazione:
% [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))]]>
nota: questo schizzo, ovviamente, è molto probabilmente bisogno di ulteriori test.
Se si decide di eseguire il benchmark dei miglioramenti (se presenti), si prega di non utilizzare istruzioni IO (come writeln), dal momento che quelli avrebbero comunque dominato i tempi di esecuzione.
Il modo più veloce probabilmente non sarà nemmeno una serie di if-then-elses, ma piuttosto un insieme di clausole per ogni caso. Ulteriore vantaggio: sarai in grado di utilizzare queste clausole in più direzioni. Controlla 'term_expansion/2' e' goal_expansion/2'. Per riscrivere i termini al momento della compilazione. Vedi 'maplist/2' di SWI-Prolog in' library (apply_macros) 'per vedere come si possono compilare tali costrutti per le chiamate di predicati ausiliari. – mat
Esiste già un modo per fare esattamente ciò che descrivi: un predicato con più clausole, dove il primo argomento è l'espressione "interruttore" (come sottolinea anche @mat ....). Perché stai scartando questo costrutto idiomatico, ampiamente usato? –
PS. Se la domanda riguarda effettivamente come eseguire l'espansione in fase di compilazione, allora si tratta di una domanda diversa. –