2016-03-03 9 views
7

W predykatów Prologu, często pisać powtarzające instrukcje warunkowe jak ten, ale szkoda, że ​​nie mógł być napisany bardziej zwięźle:oświadczenia przełącznika w Prologu

output(Lang, Type, Output) :- 
    (Lang = javascript -> 
     Output = ["function", Type]; 
    Lang = ruby -> 
     Output = ["def", Type]; 
    Lang = java -> 
     Output = [Type]). 

Czy byłoby możliwe, aby zastąpić tę serię instrukcji warunkowych z bardziej zwięzłe oświadczenie przełączające?

+1

Nawiasy pisane wokół warunków są zbędne. Zamiast tego powinieneś umieścić pojedynczą parę nawiasów wokół całej konstrukcji (a-> b; c-> d; e). Jest to najlepsza praktyka, aby uniknąć niespodzianek, gdy chcesz połączyć warunkowe z innymi celami. – jschimpf

+0

@jschimpf Naprawiłem problem, więc teraz wydaje się bardziej zwięzły. –

Odpowiedz

6

W Prologu jest to dość łatwe do zdefiniowania własnych struktur sterujących, za pomocą meta-orzeczników (predykatów, które mają cele lub predykatów jako argumenty).

Na przykład, można zaimplementować przełącznik skonstruować jak

switch(X, [ 
    a : writeln(case1), 
    b : writeln(case2), 
    c : writeln(case3) 
]) 

definiując

switch(X, [Val:Goal|Cases]) :- 
    (X=Val -> 
     call(Goal) 
    ; 
     switch(X, Cases) 
    ). 

jeśli to konieczne, to można wtedy osiągnąć poprzez transformację kompilacji jako obsługiwany przez wiele Prolog systemy (inline/2 w ECLiPSe lub rozszerzenie celu w kilku innych systemach).

Dzięki deklaracjom operatora można dostosować składnię do niemal wszystkiego, co się podoba.

1

nieco krótszy:

output(Lang, Type, Output) :- 
    (Lang, Output) = (javascript, ["function", Type]) ; 
    (Lang, Output) = (ruby, ["def", Type]) ; 
    (Lang, Output) = (java, [Type]). 

idiomatyczne:

output(Lang, Type, Output) :- 
    memberchk(Lang-Output, [ 
    javascript - ["function", Type], 
    ruby - ["def", Type], 
    java - [Type] 
    ]). 
+2

Używanie memberchk/2 jest dość nieefektywnym sposobem na kopiowanie struktury implementacji Prolog (które są AFAIK wszystkie aktualnie aktywnie obsługiwane implementacje), ponieważ najpierw kopiuje całą strukturę do stosu, następnie uruchamia memberchk/2 i na koniec pozostawia wspomnienie skopiowanej struktury do GC. Pierwsza jest bardziej akceptowalna, ale używanie oddzielnych klauzul jako następnej odpowiedzi jest prawdziwą metodą Prolog: spójną i szybką z powodu indeksowania klauzul. –

+0

@JanWielemaker: Zgadzam się, moja odpowiedź nie jest dobra ... Ponadto mój pierwszy fragment nie jest odpowiednikiem kodu OP. ale nie ma oddzielnych klauzul, bez cięć ... – CapelliC

6

Wydaje się, że wiele klauzul są wykonane w tym przypadku zastosowania, a także dość zwięzłe.

output(javascript, Type, ["javascript", Type]). 
output(ruby, Type, ["def", Type]). 
output(java, Type, [Type]). 
+0

Oczywiście, będzie to zwięzłe, jeśli predykat ma małą liczbę argumentów. Wciąż szukam bardziej zwięzłego sposobu implementacji instrukcji switch w Prologu. –

+0

Na pewno wiele klauzul nie jest tworzonych dla tego przypadku użycia. Są ** głównym ** narzędziem kontroli przepływu dostępnym w Prologu. Jako takie oczywiście obejmują one ten banalny przypadek użycia. – CapelliC