Le défi consiste à écrire un interprète pour le calcul lambda non typé dans le moins de caractères possible. Nous définissons le calcul lambda non typé comme suit:
Syntaxe
Il existe trois types d'expressions:
Une expression lambda a la forme
(λ x. e)
oùx
pourrait être n'importe quel nom de variable juridique ete
toute expression juridique. Icix
s'appelle le paramètre ete
s'appelle le corps de la fonction.Par souci de simplicité, nous ajoutons la restriction supplémentaire selon laquelle il ne doit pas y avoir de variable portant le même nom que celle
x
actuellement dans la portée. Une variable commence à se trouver dans la portée lorsque son nom apparaît entre(λ
et.
et cesse de se trouver dans la portée correspondante)
.- L'application de fonction a la forme
(f a)
oùf
eta
sont des expressions juridiques. Icif
s'appelle la fonction eta
s'appelle l'argument. - Une variable a la forme
x
oùx
est un nom de variable légal.
Sémantique
Une fonction est appliquée en remplaçant chaque occurrence du paramètre dans le corps de la fonction par son argument. Plus formellement, une expression de la forme ((λ x. e) a)
, où x
est un nom de variable et e
et a
sont des expressions, est évaluée (ou réduite) à l'expression e'
où e'
est le résultat du remplacement de chaque occurrence de x
in e
par a
.
Une forme normale est une expression qui ne peut plus être évaluée.
Le défi
Votre mission, si vous l'acceptez, est d'écrire un interpréteur qui prend en entrée une expression du calcul lambda non typé ne contenant aucune variable libre et produit en sortie la forme normale de l'expression (ou une expression qui lui correspond parfaitement) . Si l'expression n'a pas de forme normale ou s'il ne s'agit pas d'une expression valide, le comportement n'est pas défini.
La solution avec le plus petit nombre de caractères gagne.
Quelques notes:
- Les entrées peuvent être lues à partir de stdin ou d'un nom de fichier donné en argument de ligne de commande (vous devez uniquement implémenter l'un ou l'autre, pas les deux). La sortie passe à stdout.
- Vous pouvez également définir une fonction qui prend l’entrée sous forme de chaîne et renvoie le résultat sous forme de chaîne.
- Si les caractères non-ASCII vous posent problème, vous pouvez utiliser le caractère barre oblique inverse (
\
) au lieu de λ. - Nous comptons le nombre de caractères, pas d'octets, donc même si votre fichier source est codé sous la forme d'unicode, λ compte pour un caractère.
- Les noms de variables légales consistent en une ou plusieurs lettres minuscules, c'est-à-dire des caractères compris entre a et z (inutile de prendre en charge les noms alphanumériques, les majuscules ou les lettres non latines - bien que cela n'invalidera pas votre solution, bien sûr).
- En ce qui concerne ce défi, aucune parenthèse n'est optionnelle. Chaque expression lambda et chaque application de fonction seront entourées d’exactement une paire de parenthèses. Aucun nom de variable ne sera entouré de parenthèses.
- Le sucre syntaxique comme écrire
(λ x y. e)
pour(λ x. (λ y. e))
n'a pas besoin d'être soutenu. - Si une profondeur de récursivité supérieure à 100 est requise pour évaluer une fonction, le comportement n'est pas défini. Cela devrait être plus que suffisamment bas pour être implémenté sans optimisation dans toutes les langues et toujours assez grand pour pouvoir exécuter la plupart des expressions.
- Vous pouvez également supposer que l'espacement sera comme dans les exemples, c'est-à-dire pas d'espaces au début et à la fin de l'entrée ou avant un
λ
ou.
et exactement un espace après un.
et entre une fonction et son argument et après unλ
.
Exemple d'entrée et de sortie
Contribution:
((λ x. x) (λ y. (λ z. z)))
Sortie:
(λ y. (λ z. z))
Contribution:
(λ x. ((λ y. y) x))
Sortie:
(λ x. x)
Contribution:
((λ x. (λ y. x)) (λ a. a))
Sortie:
(λ y. (λ a. a))
Contribution:
(((λ x. (λ y. x)) (λ a. a)) (λ b. b))
Sortie:
(λ a. a)
Contribution:
((λ x. (λ y. y)) (λ a. a))
Sortie:
(λ y. y)
Contribution:
(((λ x. (λ y. y)) (λ a. a)) (λ b. b))
Sortie:
(λ b. b)
Contribution:
((λx. (x x)) (λx. (x x)))
Sortie: n'importe quoi (Ceci est un exemple d'expression qui n'a pas de forme normale)
Contribution:
(((λ x. (λ y. x)) (λ a. a)) ((λx. (x x)) (λx. (x x))))
Résultat:
(λ a. a)
(Ceci est un exemple d'expression qui ne se normalise pas si vous évaluez les arguments avant l'appel de la fonction et, malheureusement, un exemple pour lequel ma tentative de solution a échoué.)Contribution:
((λ a. (λ b. (a (a (a b))))) (λ c. (λ d. (c (c d)))))
Sortie:
`(λ a. (λ b. (a (a (a (a (a (a (a (a b))))))))))
Ceci calcule 2 ^ 3 en chiffres d'église.
(\y. a)
.