Herausforderung
Ihre Herausforderung besteht darin, einen Dolmetscher für eine Lispel-ähnliche Sprache zu entwerfen, die von nun an geprägt wird: GLisp . Der Programmcode für GLisp besteht aus einer beliebigen Anzahl geschachtelter Ausdrücke in Klammern in der folgenden Form:
(func arg1 arg2 ...)
Beachten Sie, dass der Interpreter vor und nach eckigen Klammern, Funktionen und Argumenten zusätzliche Leerzeichen zulassen muss.
Typen
Sie implementieren vier Typen: Integer, List, Boolean und Function. Ganzzahlen und Boolesche Werte können mit ihrer eigenen Syntax explizit in den Quellcode eingefügt werden. Ihr Interpreter muss davon ausgehen, dass eine Folge von numerischen Zeichen eine Ganzzahl darstellt (Sie müssen keine Syntax implementieren, um negative Ganzzahlen explizit einzufügen). Ihr Dolmetscher muss dies auch annehmen true
und false
als Boolesche Werte bezeichnet werden. Funktionen können vom Benutzer nicht explizit definiert werden und geben immer einen einzelnen Wert zurück (eine Liste beliebiger Länge zählt als ein einzelner Wert).
Funktionen
Die folgenden Funktionen müssen implementiert werden und haben das Format Funktion , Arität . Wenn nach einer Arität n
ein Pluszeichen folgt, bedeutet dies n
oder mehrere Argumente. Sie können davon ausgehen, dass alle Argumente für eine Funktion vom selben Typ sind, sofern nicht anders angegeben. Sie können auch davon ausgehen, dass kein Argument dieser Funktion jemals von diesem Typ sein wird, wenn für einen Certian-Typ kein Verhalten angegeben ist. In der folgenden Abbildung wird auf die Argumente Bezug genommen:
(func argument1 argument2 ... argumentn)
+ , 2+
- Wenn alle Argumente vom Typ Integer sind , müssen Sie die Summe der Argumente zurückgeben
- Wenn alle Argumente vom Typ Liste sind , müssen Sie die Verkettung der Argumente in aufsteigender Reihenfolge (
arg1+arg2+ ...
) zurückgeben. - Wenn alle Argumente vom Typ Boolean sind , müssen Sie die logische Folge Alle der Argumente zurückgeben
(+ 1 2 3 4 5) -> 15
(+ (list 1 2) (list 3 4)) -> (list 1 2 3 4)
(+ true true true) -> true
- , 2+
- Wenn alle Argumente vom Typ Integer sind , müssen Sie die Differenz der Argumente (
arg1-arg2- ...
) zurückgeben. - Wenn alle Argumente vom Typ Boolean sind , müssen Sie die logische Beliebige der Argumentfolge zurückgeben
(- 8 4 3) -> 1
(- 0 123) -> -123
(- true false false true false) -> true
- Wenn alle Argumente vom Typ Integer sind , müssen Sie die Differenz der Argumente (
* , 2+
- Wenn alle Argumente vom Typ Integer sind , müssen Sie das Produkt der Argumente zurückgeben
- Wenn ein Argument vom Typ List und das andere vom Typ Integer ist (Sie können davon ausgehen, dass nur diese Argumente angegeben werden), müssen Sie wiederholt eine neue Liste mit den Elementen zurückgeben.
arg1
arg2
(* 1 2 3 4 5) -> 120
(* (list 1 2 3) 2) -> (list 1 2 3 1 2 3)
/ , 2+
- Wenn alle Argumente vom Typ Integer sind , müssen Sie den Quotienten der Argumente (
arg/arg2/ ...
) zurückgeben (Sie können davon ausgehen, dass die Division nacheinander erfolgt und der Dezimalteil bei jedem Schritt abgeschnitten wird). - Wenn ein Argument vom Typ List und das andere vom Typ Function ist , müssen Sie die resultierende List zurückgeben, nachdem
arg2
jeder Wert zugeordnet wurde (/ 100 10 3) -> 3
(/ (list 1 2 3) inc) -> (list 2 3 4)
- Wenn alle Argumente vom Typ Integer sind , müssen Sie den Quotienten der Argumente (
% , 2
- Wenn alle Argumente vom Typ Integer sind , müssen Sie den Modul der Argumente zurückgeben
(% 4 2) -> 0
= , 2+
- Wenn sowohl die Art und Wert aller Argumente gleich ist, müssen Sie true zurück. Andernfalls geben Sie false zurück.
(= 0 0 0) -> true
(= 0 false (list)) -> false
Liste , 0+
- Sie müssen eine Liste aller Argumente unabhängig vom Typ zurückgeben. Wenn keine Argumente angegeben werden, müssen Sie eine leere Liste zurückgeben
(list 3 4 (list 5)) -> (list 3 4 (list 5))
inc , 1
- Wenn das Argument vom Typ Integer ist , müssen Sie die Ganzzahl um eins erhöht zurückgeben
- Wenn das Argument vom Typ Liste ist , müssen Sie die Liste um eine Drehung im Uhrzeigersinn drehen
(inc 1) -> 2
(inc (list 1 2 3)) -> (list 3 1 2)
Dezember , 1
- Wenn das Argument vom Typ Integer ist , müssen Sie die um eins dekrementierte Ganzzahl zurückgeben
- Wenn das Argument vom Typ Liste ist , müssen Sie die Liste um eine einzelne Drehung gegen den Uhrzeigersinn drehen
(dec 1) -> 0
(dec (list 1 2 3)) -> (list 2 3 1)
wenn , 3
- Wenn Sie drei Argumente eines beliebigen Typs angeben : Wenn der Wahrheitswert von
arg1
wahr ist, geben Sie zurückarg2
, andernfalls geben Sie zurückarg3
(if (not (list 1)) 8 false) -> false
- Wenn Sie drei Argumente eines beliebigen Typs angeben : Wenn der Wahrheitswert von
nicht , 1
- Wenn ein Argument eines beliebigen Typs angegeben wird und der Wahrheitswert von
arg1
False ist, geben Sie zurücktrue
, andernfalls geben Sie zurückfalse
. (not (list)) -> true
- Wenn ein Argument eines beliebigen Typs angegeben wird und der Wahrheitswert von
len , 1
- Wenn Sie ein Argument vom Typ List übergeben , geben Sie die Länge von zurück
arg1
(len (list 4 2 true (list 3) (list))) -> 5
- Wenn Sie ein Argument vom Typ List übergeben , geben Sie die Länge von zurück
Wahrheitstabelle:
0, (list), false -> false
, wo (list)
bezeichnet eine leere Liste. Alles andere ist true
.
Ihr Interpreter kann entweder ein vollständiges Programm sein, das die Quelleingabe aus stdin oder einer Datei liest, oder eine Funktion, die die Quelle als Zeichenfolge verwendet und den Ausgabewert zurückgibt.
Ist ersteres der Wahl der Ausgang für Integers ist einfach Zahlen, für Boolesche Werte ist true
oder false
und für Listen ist ein Raum Folge von Werten in Klammern getrennt sind (z. (1 2 3 4 (5 6 7))
Bezeichnet (list 1 2 3 4 (list 5 6 7))
).
Wenn Sie Letzteres auswählen, muss der Wert in dem entsprechenden Typ der Implementierungssprache oder, falls kein ähnlicher Typ vorhanden ist, in einem benutzerdefinierten Typ zurückgegeben werden. Listen können als Arrays oder Vektoren zurückgegeben werden , wenn die Sprache nicht hat Liste Typen, Boolesche Werte sollten als Typ Boolean in der Sprache zurückgegeben werden, oder einem benutzerdefinierten Typ , wenn die Sprache nicht unterstützt werden .
Testfälle
(list 1 2 3 (list 4 5 true)) -> (1 2 3 (4 5 true))
(/ 4000 (+ 1 2 3 4 (* 5 8))) -> 80
(+ (not (- (len (list 5 6 7)) (/ 10 3))) true) -> true
(if ( len (list ) ) 4 (if (+ (= 8 8 8) (not (list 4))) 8 5)) -> 5
Klarstellungen
- Ihr Interpreter behandelt möglicherweise ungültige Eingaben auf eine von Ihnen gewählte Weise, darf jedoch keine Ausnahme auslösen (es kann jedoch vorkommen, dass eine Fehlermeldung ausgegeben und der Vorgang reibungslos beendet wird).
- Funktionen werten Argumente immer von links nach rechts aus
- Eine ungültige Eingabe ist eine syntaktisch falsche Eingabe. Dies beinhaltet, ohne darauf beschränkt zu sein, nicht übereinstimmende Klammern, Division durch Null und teilweise angewendete Funktionen (außer für den Bonus).
- Für
=
, wenn eine der Werte unterschiedlich sind oder eine der Arten unterschiedlich sind, Rückkehrfalse
Boni
- Punktzahl * 0,8, wenn Sie teilweise angewandte Funktionen unterstützen. Zum Beispiel
((+ 2) 3)
wäre das das gleiche wie(+ 2 3)
, erlaubt aber Dinge wie(/ (list 1 2 3) (+ 2))
. Sie können davon ausgehen, dass eine Funktion teilweise angewendet wird, wenn sie weniger als die Mindestanzahl von Argumenten empfängt - Ergebnis * 0,85, wenn Sie die Argumente, auf die angewendet wird, nur bewerten,
if
wenn sie zurückgegeben werden
Das ist Code-Golf, also gewinnt der Interpreter mit der niedrigsten Bytezahl!
(+ 3 (if false 5))
? Was bedeutet eigentlich "nichts zurückgeben"? Sie haben keinen Einheitentyp angegeben, der zurückgestimmt werden soll
(+ bool bool...)
logisches UND und (- bool bool...)
logisches ODER? Die Standard-Ringnotation würde +
für OR und *
für AND verwendet. 2. Soll "ungültige Eingabe" Fälle abdecken, (/ 2 0)
die syntaktisch korrekt sind? 3. =
Falls die Werte nicht alle gleich sind, sollte sie zurückgegeben werden false
? 4. Die Definition von not
scheint rückwärts zu sein. 5. Was sind die Token? Sie sagen, dass der Interpreter zusätzliche Leerzeichen verarbeiten muss, aber Sie sagen nicht, auf welche Leerzeichen er sich verlassen kann. Für komplexe Fragen wie diese sollten Sie unbedingt die Sandbox verwenden, damit die Spezifikation überprüft werden kann.
((+ 2 3) 4)
gleich 9
oder ein Fehler? Insbesondere für var-arg-Funktionen ist nicht klar, wann die Anwendung teilweise berücksichtigt werden sollte. Es wird noch matschiger mit Dingen wie((if true (+ 2 3) (- 5)) 4)
(if (not (array 1)) 8 false) -> false
?