Défi
Votre défi est de concevoir un interprète pour une langue de type lisp, qui sera désormais inventée: GLisp . Le code du programme pour GLisp consistera en une quantité arbitraire d'expressions imbriquées désignées par des crochets, sous la forme suivante:
(func arg1 arg2 ...)
Notez que l'interpréteur doit autoriser les espaces blancs superflus avant et après les crochets, les fonctions et les arguments.
Les types
Vous implémenterez quatre types, Integer, List, Boolean et Function. Les entiers et les valeurs booléennes peuvent être insérés explicitement dans le code source avec leur propre syntaxe. Votre interprète doit supposer qu'une série de caractères numériques dénote un entier (vous n'avez pas à implémenter une syntaxe pour insérer explicitement des entiers négatifs). Votre interprète doit également supposer cela true
et false
sont des valeurs booléennes désignées. Les fonctions ne peuvent pas être définies explicitement par l'utilisateur et renverront toujours une seule valeur (une liste de toute longueur compte comme une seule valeur).
Les fonctions
Les fonctions suivantes doivent être implémentées et sont au format Fonction , Arity . Si une entité n
est précédée d'un signe plus, cela indique un n
ou plusieurs arguments. Vous pouvez supposer que tous les arguments donnés à une fonction sont du même type, sauf indication contraire. Vous pouvez également supposer que si aucun comportement n'est spécifié pour un type certian, vous pouvez supposer qu'aucun argument de cette fonction ne sera jamais de ce type. Les arguments seront appelés comme dans le diagramme suivant:
(func argument1 argument2 ... argumentn)
+ , 2+
- Si tous les arguments sont de type Integer , vous devez renvoyer la somme des arguments
- Si tous les arguments sont du type List , vous devez renvoyer la concaténation des arguments dans l'ordre croissant (
arg1+arg2+ ...
) - Si tous les arguments sont de type booléen , vous devez renvoyer l'ensemble logique de la séquence d'arguments
(+ 1 2 3 4 5) -> 15
(+ (list 1 2) (list 3 4)) -> (list 1 2 3 4)
(+ true true true) -> true
- , 2+
- Si tous les arguments sont de type Integer , vous devez renvoyer la différence des arguments (
arg1-arg2- ...
) - Si tous les arguments sont de type booléen , vous devez renvoyer la logique quelconque de la séquence d'arguments
(- 8 4 3) -> 1
(- 0 123) -> -123
(- true false false true false) -> true
- Si tous les arguments sont de type Integer , vous devez renvoyer la différence des arguments (
* , 2+
- Si tous les arguments sont de type Integer , vous devez renvoyer le produit des arguments
- Si un argument est de type List et l'autre est de type Integer (vous pouvez supposer que ce ne seront que les seuls arguments donnés), vous devez renvoyer une nouvelle List avec les éléments à
arg1
plusieursarg2
reprises. (* 1 2 3 4 5) -> 120
(* (list 1 2 3) 2) -> (list 1 2 3 1 2 3)
/ , 2+
- Si tous les arguments sont du type Entier , vous devez renvoyer le quotient des arguments (
arg/arg2/ ...
) (vous pouvez supposer que la division est effectuée séquentiellement et que la partie décimale à chaque étape est tronquée) - Si un argument est de type Liste et l'autre est de type Fonction , vous devez renvoyer la Liste résultante après
arg2
avoir été mappée sur chaque valeur (/ 100 10 3) -> 3
(/ (list 1 2 3) inc) -> (list 2 3 4)
- Si tous les arguments sont du type Entier , vous devez renvoyer le quotient des arguments (
% , 2
- Si tous les arguments sont de type Integer , vous devez renvoyer le module des arguments
(% 4 2) -> 0
= , 2+
- Si à la fois le type et la valeur de tous les arguments sont les mêmes, vous devez retourner vrai. Sinon, retournez false.
(= 0 0 0) -> true
(= 0 false (list)) -> false
liste , 0+
- Vous devez renvoyer une liste de tous les arguments, quel que soit leur type. Si aucun argument n'est donné, vous devez renvoyer une liste vide
(list 3 4 (list 5)) -> (list 3 4 (list 5))
inc , 1
- Si l'argument est de type Integer , vous devez renvoyer Integer incrémenté d'une unité.
- Si l'argument est de type Liste , vous devez renvoyer la Liste tournée dans le sens horaire d'une seule rotation
(inc 1) -> 2
(inc (list 1 2 3)) -> (list 3 1 2)
déc , 1
- Si l'argument est de type Integer , vous devez renvoyer l' Integer décrémenté d'une unité
- Si l'argument est de type Liste , vous devez renvoyer la Liste tournée dans le sens antihoraire une seule rotation
(dec 1) -> 0
(dec (list 1 2 3)) -> (list 2 3 1)
si , 3
- Si on donne trois arguments de n'importe quel type: Si la valeur de vérité de
arg1
est vraie, retournearg2
, sinon retournearg3
(if (not (list 1)) 8 false) -> false
- Si on donne trois arguments de n'importe quel type: Si la valeur de vérité de
non , 1
- Si un argument de n'importe quel type lui est donné, si la valeur de vérité de
arg1
est False, returntrue
, else returnfalse
. (not (list)) -> true
- Si un argument de n'importe quel type lui est donné, si la valeur de vérité de
len , 1
- Si un argument de type List est donné , retourne la longueur de
arg1
(len (list 4 2 true (list 3) (list))) -> 5
- Si un argument de type List est donné , retourne la longueur de
Table de vérité:,
0, (list), false -> false
où (list)
dénote une liste vide. Tout le reste l'est true
.
Votre interpréteur peut être soit un programme complet qui lit l'entrée source depuis stdin ou un fichier, soit une fonction qui prend la source comme chaîne et renvoie la valeur de sortie.
Si vous choisissez le premier, la sortie pour les entiers est simplement des nombres, pour les booléens est true
ou false
, et pour les listes est une séquence de valeurs séparées par des espaces entre crochets (par exemple, (1 2 3 4 (5 6 7))
dénote (list 1 2 3 4 (list 5 6 7))
).
Si vous choisissez ce dernier, la valeur doit être retournée dans le type correspondant du langage d'implémentation ou, s'il n'existe aucun type similaire, un type personnalisé. Listes peuvent être renvoyées sous forme de tableaux ou de vecteurs si la langue n'a pas de type Liste , les booléens doivent être renvoyés sous forme de type booléen dans la langue ou un type personnalisé si la langue ne les prend pas en charge.
Cas de 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
Clarifications
- Votre interprète peut traiter les entrées invalides de la manière que vous choisissez, mais ne doit pas lever d'exception (cependant, il peut imprimer un message d'erreur et quitter en douceur)
- Les fonctions évalueront toujours les arguments de gauche à droite
- Une entrée non valide est une entrée qui est syntaxiquement incorrecte. Cela inclut, mais sans s'y limiter, les parenthèses incompatibles, la division par zéro et les fonctions partiellement appliquées (sauf si vous optez pour le bonus)
- Pour
=
, si l'une des valeurs est différente ou l' un des types est différent, retournezfalse
Bonus
- Score * 0,8 si vous supportez des fonctions partiellement appliquées. Par exemple,
((+ 2) 3)
serait le même que(+ 2 3)
, mais permet des choses telles que(/ (list 1 2 3) (+ 2))
. Vous pouvez supposer qu'une fonction est partiellement appliquée si elle reçoit moins que son nombre minimum d'arguments - Score * 0,85 si vous n'évaluez pas les arguments appliqués à
if
moins qu'ils ne soient retournés
C'est du code-golf, donc l'interprète avec le plus petit nombre d'octets gagne!
(+ 3 (if false 5))
? De manière générale, qu'est-ce que "ne rien retourner"? Vous n'avez spécifié aucun type d'unité à réaccorder
(+ bool bool...)
logique ET et (- bool bool...)
OU logique? La notation en anneau standard utiliserait +
pour OR et *
pour AND. 2. La "saisie invalide" est-elle destinée à couvrir des cas comme ceux (/ 2 0)
qui sont syntaxiquement corrects? 3. Car =
, si les valeurs ne sont pas toutes identiques, doit-elle revenir false
? 4. La définition de not
semble être à l'envers. 5. Quels sont les jetons? Vous dites que l'interpréteur doit gérer des espaces supplémentaires, mais vous ne dites pas sur quel espace il peut compter. Pour des questions complexes comme celle-ci, vous devez vraiment utiliser le bac à sable afin que la spécification puisse être vérifiée.
((+ 2 3) 4)
égal à 9
ou une erreur? Notamment, pour les fonctions var-arg, il n'est pas clair quand il faut considérer l'application comme partielle. Il devient encore plus boueux avec des choses comme((if true (+ 2 3) (- 5)) 4)
(if (not (array 1)) 8 false) -> false
?