Le calcul SKI est une variante du calcul Lambda qui n'utilise pas d'expressions lambda. Au lieu de cela, seule l'application et les combinateurs S , K et I sont utilisés. Dans ce défi, votre tâche consiste à traduire les termes SKI en termes Lambda sous forme normale β .
Spécification d'entrée
L'entrée est un terme SKI dans la représentation textuelle suivante. Vous pouvez choisir de recevoir un retour à la ligne facultatif. L'entrée est composé des caractères S
, K
, I
, (
, et )
et satisfait la grammaire suivante (sous forme ABNF) avec sterm
étant le symbole de début:
sterm = sterm combinator ; application
sterm = combinator ;
sterm = '(' sterm ')' ; grouping
combinator = 'S' | 'K' | 'I' ; primitives
Spécifications de sortie
La sortie est un terme lambda sans variable libre dans la représentation textuelle suivante. Vous pouvez choisir de sortir une nouvelle ligne de fin facultative. La sortie doit satisfaire la grammaire suivante sous forme ABNF en lterm
étant le symbole de début:
lterm = lterm operand ; application
lterm = ALPHA '.' lterm ; lambda
lterm = operand
operand = '(' lterm ')' ; grouping
operand = ALPHA ; variable (a letter)
Contraintes
Vous pouvez supposer que l'entrée a une forme normale β. Vous pouvez supposer que la forme normale β utilise au plus 26 variables différentes. Vous pouvez supposer que l'entrée et la sortie sont représentables en 79 caractères.
Exemples d'entrées
Voici quelques exemples d'entrées. La sortie est une sortie possible pour l'entrée donnée.
input output
I a.a
SKK a.a
KSK a.b.c.ac(bc)
SII a.aa
Notation
La solution la plus courte en octets l'emporte. Les failles communes sont interdites.
sterm
etlterm
utiliser l'associativité gauche lorsque les crochets sont manquants.SKI
commeS(KI)
.Réponses:
Haskell , 232 octets
Essayez-le en ligne!
Comment ça marche
Ceci est une interface d'analyse différente de ma réponse à «Écrire un interprète pour le calcul lambda non typé» , qui a également une version non golfée avec de la documentation.
En bref,
Term = T (Char -> String)
est le type de termes de calcul lambda, qui savent comment s’appliquer à d’autres termes (a :: Term -> Term -> Term
) et comment s’afficher en tant queString
((%) :: Term -> Char -> String
), étant donné une nouvelle variable initiale comme aChar
. Nous pouvons convertir une fonction sur des termes en un terme avecl :: (Term -> Term) -> Term
, et parce que l'application du terme résultant appelle simplement la fonction (a (l f) == f
), les termes sont automatiquement réduits à leur forme normale lorsqu'ils sont affichés.la source
Rubis, 323 octets
Je ne peux pas croire que ce morceau de merde fonctionne du tout:
Utiliser la substitution de regex pour effectuer une réduction β sur des chaînes brutes est un truc de Tony-the-Pony. Néanmoins, sa sortie semble correcte au moins pour des tests faciles:
Voici la gestion
K(K(K(KK)))
avec une sortie de débogage, ce qui prend environ 7 secondes sur mon ordinateur portable, car la récursivité des expressions régulières est lente . Vous pouvez voir sa conversion α en action!la source
Python 2, 674
Remarque: après
while 1:
, 3 lignes sont en retrait avec un caractère de tabulation.Il s'agit essentiellement du code derrière http://ski.aditsu.net/ , traduit en python, grandement simplifié et très utilisé.
Référence: (c'est probablement moins utile maintenant que le code est compressé)
V = terme variable
A = terme d'application
L = terme lambda
c = compteur de variables
p = remplacer la variable par le terme
r = réduire
m = renumérotation variable finale
u = renumérotation variable interne (pour les termes dupliqués)
s = conversion de chaîne
(paramètre s = self)
C = caractère (s) de séparation pour la conversion de chaînes
I, K, S: combinateurs
E = analyse
Exemples:
(ce ↑ est attendu car
SII(SII)
irréductible)Merci Mauris et Sp3000 d'avoir aidé à tuer un tas d'octets :)
la source
def m(a,b,c):return foo
enm=lambda a,b,c:foo
classes internes, ce qui pourrait vous faire économiser beaucoup d'octets.a.b.c.a(c)(b(c))
comme une expression lambda valide: qu'est-ce que c'est(c)
?Lisp commun, 560 octets
"Enfin, j'ai trouvé une utilisation pour
PROGV
."Non golfé
Réduction bêta
Les variables sont liées dynamiquement pendant la réduction avec
PROGV
de nouveaux symboles Common Lisp, en utilisantMAKE-SYMBOL
. Cela permet d'éviter les collisions de noms (par exemple, l'observation indésirable des variables liées). J'aurais pu utiliserGENSYM
, mais nous voulons avoir des noms conviviaux pour les symboles. C'est pourquoi les symboles sont nommés avec les lettres de aà z(comme le permet la question).N
représente le code de caractère de la prochaine lettre disponible dans la portée actuelle et commence par 97, alias a.Voici une version plus lisible de
R
(sans laW
macro):Résultats intermédiaires
Analyse de la chaîne:
Réduire:
(Voir trace d'exécution)
Jolie impression:
Les tests
Je réutilise la même suite de tests que la réponse Python:
Le 8ème exemple de test est trop grand pour le tableau ci-dessus:
a.a.a.a.a.b.a
est correct et ne pas utiliser autant de lettres que la réponse Python, où les liaisons àa
,b
,c
etd
ne sont pas référencés.Performance
Faire une boucle sur les 7 tests réussis ci-dessus et collecter les résultats est immédiat (sortie SBCL):
Faire le même test une centaine de fois conduit à ... "Thread local storage exhausted" sur SBCL, en raison d'une limitation connue concernant les variables spéciales. Avec CCL, appeler la même suite de tests 10000 fois prend 3,33 secondes.
la source