minimalna próba: utwórz plik o nazwie 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).
następnie używać go jak jak zwykle: na przykład w pliku 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)
]).
po kompilacji switch_test. pl:
?- listing(test2).
test2(A) :-
( A=a
-> writeln(case1)
; A=b
-> writeln(case2)
; A=c
-> writeln(case3)
).
true.
edit powodu stwardnienia zamów uests, tutaj jest schemat kompilacja oddzielić punktach:
:- 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).
teraz skrypt testowy został owinięty w module, aby ułatwić dalszą listę:
:- 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)
]).
a wynik po kompilacji 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).
aby ułatwić debugowanie:
?- debug(switch).
że wysyła wiadomość jak to podczas kompilacji:
% [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))]]>
uwaga: ten szkic oczywiście jest bardzo prawdopodobnie potrzeba więcej badań.
Jeśli zdecydujesz się na benchmarku ulepszenia (jeśli w ogóle), proszę nie używać stwierdzeń IO (jak writeln), gdyż te będą dominować w każdym razie te czasy realizacji.
Najszybszy sposób najprawdopodobniej nie będzie nawet serią elementów if-then-elses, ale raczej zbiorem klauzul dla każdego przypadku. Dodatkowa korzyść: Będziesz mógł używać tych klauzul w większej liczbie kierunków. Sprawdź 'term_expansion/2' i' goal_expansion/2'. Aby przepisać terminy w czasie kompilacji. Zobacz "lista-map/2" SWI-Prolog w 'bibliotece (apply_macros)', aby zobaczyć, w jaki sposób można skompilować takie konstrukcje z wywołaniami predykatów pomocniczych. – mat
Istnieje już sposób, aby dokładnie to, co opisujesz: predykat z wieloma klauzulami, gdzie pierwszym argumentem jest wyrażenie "switch" (tak jak @mat również wskazuje ....). Dlaczego odrzucasz tę idiomatyczną, szeroko stosowaną konstrukcję? –
PS. Jeśli rzeczywiście chodzi o to, jak przeprowadzić ekspansję w czasie kompilacji, to w rzeczywistości jest to inne pytanie. –