2016-03-03 3 views
7

In Prolog-Prädikate, schreibe ich oft wiederholende bedingte Anweisungen wie diese, aber ich wünschte, sie prägnanter geschrieben werden könnte:Schalter Aussagen in Prolog

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

Wäre es möglich, diese Reihe von bedingten Anweisungen ersetzen eine prägnantere switch-statement?

+1

Die Klammern, die Sie über die Bedingungen geschrieben haben, sind redundant. Sie sollten stattdessen ein einzelnes Klammerpaar um das gesamte (a-> b; c-> d; e) Konstrukt platzieren. Dies ist die beste Vorgehensweise, um Überraschungen zu vermeiden, wenn Sie das Konditional mit anderen Zielen verbinden möchten. – jschimpf

+0

@jschimpf Ich habe das Problem behoben, so scheint es nun prägnanter. –

Antwort

6

In Prolog es ganz einfach ist Ihre eigenen Kontrollstrukturen zu definieren, unter Verwendung von Meta-Prädikaten (Prädikate, die Ziele oder Prädikate als Argumente).

Zum Beispiel könnten Sie wie

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

durch die Definition

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

Bei Bedarf kann ein Schalter konstruieren implementieren, kann dies dann durch Kompilierung-Transformation effizienter gemacht werden, wie sie von vielen Prolog unterstützt Systeme (inline/2 in ECLiPSe oder Zielerweiterung in mehreren anderen Systemen).

Und über Operator Deklarationen können Sie die Syntax auf so ziemlich alles, was Sie möchten, zwicken.

1

etwas kürzer:

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

idiomatische:

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

Die Verwendung von memberchk/2 ist eine ziemlich ineffiziente Methode zum Kopieren von Prolog-Implementierungen (die alle derzeit aktiv gepflegten Implementierungen sind), da sie zuerst die gesamte Struktur auf den Stack kopiert, dann memberchk/2 ausführt und schließlich die Erinnerung an die kopierte Struktur zurücklässt GC. Das erste ist akzeptabler, aber die Verwendung separater Klauseln als nächstes answe ist der echte Weg von Prolog: Consise und Fast aufgrund der Indexierung von Klauseln. –

+0

@JanWielemaker: Ich stimme zu, meine Antwort ist nicht gut ... Auch mein erstes Snippet entspricht nicht dem Code von OP. aber keine getrennten Klauseln wären, ohne Kürzungen ... – CapelliC

6

Es scheint, dass mehrere Klauseln für diesen Anwendungsfall gemacht werden und auch sehr prägnant.

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

Natürlich wird es nur knapp, wenn das Prädikat eine kleine Anzahl von Argumenten hat. Ich bin immer noch auf der Suche nach einer präziseren Möglichkeit, Switch-Anweisungen in Prolog zu implementieren. –

+0

Sicher sind mehrere Klauseln für diesen Anwendungsfall nicht gemacht. Sie sind ** das wichtigste ** Kontrollfluss-Werkzeug, das in Prolog verfügbar ist. Als solche decken sie natürlich diesen banalen Anwendungsfall ab. – CapelliC