Sfida
La tua sfida è progettare un interprete per un linguaggio simile a lisp, che d'ora in poi sarà coniato: GLisp . Il codice del programma per GLisp sarà costituito da una quantità arbitraria di espressioni nidificate indicate da parentesi, nella seguente forma:
(func arg1 arg2 ...)
Si noti che l'interprete deve consentire caratteri di spazi bianchi estranei prima e dopo parentesi, funzioni e argomenti.
tipi
Implementerai quattro tipi, Intero, Elenco, Booleano e Funzione. I valori interi e booleani possono essere esplicitamente inseriti nel codice sorgente con la propria sintassi. L'interprete deve presumere che una sequenza di caratteri numerici denoti un numero intero (non è necessario implementare una sintassi per inserire esplicitamente numeri interi negativi). L'interprete deve anche presumere che true
e false
siano designati valori booleani. Le funzioni non possono essere definite esplicitamente dall'utente e restituiranno sempre un singolo valore (un Elenco di qualsiasi lunghezza conta come un singolo valore).
funzioni
Le seguenti funzioni devono essere implementate e sono nel formato Funzione , Arity . Se un Arity n
è seguito da un segno più, allora questo indica n
o più argomenti. Si può presumere che tutti gli argomenti forniti a una funzione siano dello stesso tipo, se non diversamente specificato. Si può anche presumere che se non viene specificato alcun comportamento per un tipo di certificato, si può presumere che nessun argomento di quella funzione sarà mai di quel tipo. Gli argomenti verranno indicati come nel seguente diagramma:
(func argument1 argument2 ... argumentn)
+ , 2+
- Se tutti gli argomenti sono del tipo Intero , è necessario restituire la somma degli argomenti
- Se tutti gli argomenti sono del tipo Elenco , è necessario restituire la concatenazione degli argomenti in ordine crescente (
arg1+arg2+ ...
) - Se tutti gli argomenti sono di tipo booleano , è necessario restituire tutti gli argomenti logici della sequenza
(+ 1 2 3 4 5) -> 15
(+ (list 1 2) (list 3 4)) -> (list 1 2 3 4)
(+ true true true) -> true
- , 2+
- Se tutti gli argomenti sono del tipo Intero , è necessario restituire la differenza degli argomenti (
arg1-arg2- ...
) - Se tutti gli argomenti sono di tipo booleano , è necessario restituire il logico Qualsiasi della sequenza di argomenti
(- 8 4 3) -> 1
(- 0 123) -> -123
(- true false false true false) -> true
- Se tutti gli argomenti sono del tipo Intero , è necessario restituire la differenza degli argomenti (
* , 2+
- Se tutti gli argomenti sono di tipo Intero , è necessario restituire il prodotto degli argomenti
- Se un argomento è di tipo Elenco e l'altro è di tipo Intero (si può presumere che questi saranno gli unici argomenti forniti), è necessario restituire un nuovo Elenco con gli elementi in tempi
arg1
ripetutiarg2
. (* 1 2 3 4 5) -> 120
(* (list 1 2 3) 2) -> (list 1 2 3 1 2 3)
/ , 2+
- Se tutti gli argomenti sono del tipo Integer , è necessario restituire il quoziente degli argomenti (
arg/arg2/ ...
) (è possibile supporre che la divisione venga eseguita in modo sequenziale e che la parte decimale in ogni passaggio venga troncata) - Se un argomento è di tipo Elenco e l'altro è di tipo Funzione , è necessario restituire l' elenco risultante dopo che
arg2
è stato mappato su ogni valore (/ 100 10 3) -> 3
(/ (list 1 2 3) inc) -> (list 2 3 4)
- Se tutti gli argomenti sono del tipo Integer , è necessario restituire il quoziente degli argomenti (
% , 2
- Se tutti gli argomenti sono del tipo Intero , è necessario restituire il modulo degli argomenti
(% 4 2) -> 0
= , 2+
- Se sia il tipo e il valore di tutti gli argomenti è la stessa, è necessario tornare vero. Altrimenti, restituisci false.
(= 0 0 0) -> true
(= 0 false (list)) -> false
elenco , 0+
- È necessario restituire un elenco di tutti gli argomenti, indipendentemente dal tipo. Se non viene fornito alcun argomento, è necessario restituire un elenco vuoto
(list 3 4 (list 5)) -> (list 3 4 (list 5))
inc , 1
- Se l'argomento è di tipo Integer , è necessario restituire Integer incrementato di uno
- Se l'argomento è di tipo Elenco , è necessario restituire l' elenco ruotato in senso orario di una singola rotazione
(inc 1) -> 2
(inc (list 1 2 3)) -> (list 3 1 2)
dic , 1
- Se l'argomento è di tipo Numero intero , è necessario restituire il valore intero decrementato di uno
- Se l'argomento è di tipo Elenco , è necessario restituire l' elenco ruotato in senso antiorario di una singola rotazione
(dec 1) -> 0
(dec (list 1 2 3)) -> (list 2 3 1)
se , 3
- Se vengono forniti tre argomenti di qualsiasi tipo: Se il valore di verità
arg1
è vero, restituiscearg2
, altrimenti restituiscearg3
(if (not (list 1)) 8 false) -> false
- Se vengono forniti tre argomenti di qualsiasi tipo: Se il valore di verità
no , 1
- Se viene fornito un argomento di qualsiasi tipo, se il valore di verità
arg1
è False, returntrue
, else returnfalse
. (not (list)) -> true
- Se viene fornito un argomento di qualsiasi tipo, se il valore di verità
len , 1
- Se viene fornito un argomento di tipo Elenco , restituisce la lunghezza di
arg1
(len (list 4 2 true (list 3) (list))) -> 5
- Se viene fornito un argomento di tipo Elenco , restituisce la lunghezza di
Tabella di verità:,
0, (list), false -> false
dove (list)
indica un elenco vuoto. Tutto il resto è true
.
L'interprete può essere un programma completo che legge l'input di origine da stdin o un file o una funzione che accetta l'origine come stringa e restituisce il valore di output.
Se si sceglie il primo, l'output per Integer è semplicemente un numero, per Booleans è true
o false
, e per lists è una sequenza di valori separata da spazi racchiusa tra parentesi (ad es. (1 2 3 4 (5 6 7))
Indica (list 1 2 3 4 (list 5 6 7))
).
Se si sceglie quest'ultimo, il valore deve essere restituito nel tipo corrispondente del linguaggio di implementazione o, se non esiste un tipo simile, un tipo personalizzato. Le liste possono essere restituiti come array o vettori se la lingua non ha un elenco tipo, booleani dovrebbe essere restituito come un tipo booleano nella lingua, o un tipo personalizzato, se la lingua non li supporta.
Casi test
(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
chiarimenti
- L'interprete può gestire input non validi nel modo che preferisci, ma non deve generare un'eccezione (tuttavia, può stampare un messaggio di errore ed uscire senza problemi)
- Le funzioni valuteranno sempre gli argomenti da sinistra a destra
- L'input non valido è qualsiasi input sintatticamente errato. Questo include, ma non è limitato a, parentesi non corrispondenti, divisione per zero e funzioni parzialmente applicate (a meno che non vada per il bonus)
- Per
=
, se uno dei valori sono differenti o qualsiasi dei tipi sono diversi, ritornofalse
bonus
- Punteggio * 0,8 se si supportano funzioni parzialmente applicate. Ad esempio,
((+ 2) 3)
sarebbe lo stesso di(+ 2 3)
, ma consente cose come(/ (list 1 2 3) (+ 2))
. Si può presumere che una funzione sia parzialmente applicata se riceve meno del suo numero minimo di argomenti - Punteggio * 0,85 se non si valutano gli argomenti applicati a
if
meno che non vengano restituiti
Questo è code-golf, quindi vince l'interprete con il numero di byte più basso!
(+ 3 (if false 5))
? In generale, cosa significa veramente "non restituire nulla"? Non hai specificato alcun tipo di unità da
(+ bool bool...)
AND (- bool bool...)
logico e OR logico? La notazione suoneria standard userebbe +
per OR e *
per AND. 2. Gli "input non validi" intendono coprire casi come (/ 2 0)
quelli sintatticamente corretti? 3. Perché =
, se i valori non sono tutti uguali, dovrebbe restituire false
? 4. La definizione di not
sembra essere al contrario. 5. Quali sono i token? Dici che l'interprete deve gestire spazi bianchi extra, ma non dici su quale spazio bianco può fare affidamento. Per domande complesse come questa, dovresti davvero utilizzare il sandbox in modo che le specifiche possano essere verificate.
((+ 2 3) 4)
uguale 9
o un errore? In particolare, per le funzioni var-arg, non è chiaro quando si dovrebbe considerare l'applicazione parziale. Diventa ancora più confuso con cose come((if true (+ 2 3) (- 5)) 4)
(if (not (array 1)) 8 false) -> false
?