2016-03-03 16 views
7

In predicati Prolog, che spesso scrivono istruzioni condizionali ripetitivi come questo, ma mi vorrebbero poter essere scritte in modo più conciso:istruzioni switch in Prolog

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

sarebbe possibile sostituire questa serie di istruzioni condizionali con un'affermazione più concisa?

+1

Le parentesi che hai scritto attorno alle condizioni sono ridondanti. Dovresti invece posizionare una sola coppia di parentesi attorno al costrutto intero (a-> b; c-> d; e). Questa è la migliore pratica per evitare sorprese quando si vuole unire il condizionale con altri obiettivi. – jschimpf

+0

@jschimpf Ho risolto il problema, quindi ora sembra più conciso. –

risposta

6

In Prolog è abbastanza facile definire le proprie strutture di controllo, utilizzando i meta-predicati (predicati che prendono obiettivi o predicati come argomenti).

Ad esempio, è possibile implementare un interruttore costrutto come

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

definendo

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

Se necessario, questo può quindi essere reso più efficiente compilazione tempo di trasformazione sostenuta da molti Prolog sistemi (inline/2 in ECLiPSe, o espansione dell'obiettivo in diversi altri sistemi).

E tramite le dichiarazioni dell'operatore è possibile modificare la sintassi in quasi tutto ciò che si desidera.

1

leggermente più corta:

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

idiomatica:

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

L'uso di memberchk/2 è un metodo piuttosto inefficiente per la struttura che copia le implementazioni Prolog (che sono tutte le implementazioni attualmente attivamente mantenute AFAIK) poiché dapprima copia l'intera struttura nello stack, quindi esegue memberchk/2 e infine lascia il ricordo della struttura copiata GC. Il primo è più accettabile, ma l'uso di clausole separate come la risposta successiva è il vero modo Prolog: consise e veloce a causa dell'indicizzazione della clausola. –

+0

@JanWielemaker: Sono d'accordo, la mia risposta non è buona ... Inoltre, il mio primo frammento non è equivalente al codice OP '. ma nessuna clausola separata sarebbe, senza tagli ... – CapelliC

6

Sembra che più clausole sono fatte per questo caso d'uso e anche abbastanza conciso.

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

Ovviamente, sarà conciso solo se il predicato ha un piccolo numero di argomenti. Sto ancora cercando un modo più conciso per implementare le istruzioni switch in Prolog. –

+0

Di sicuro, non vengono fatte più clausole per questo caso d'uso. Sono ** lo strumento di controllo del flusso principale ** disponibile in Prolog. Come tali, ovviamente coprono questo caso d'uso banale. – CapelliC