Introducción
Forte es un lenguaje esotérico muy peculiar basado en el concepto de modificar los valores de los números. En Forte, los números no son constantes sino variables, puede usar la LET
instrucción para asignarles nuevos valores.
Por ejemplo, después de ejecutar a LET 2=4-1
partir de ahora 2
asume el valor de 3
, lo que significa que cada vez que el valor 2
aparece en una expresión, en su lugar, se "reemplaza" por 3
. La expresión (1+1)*2
ahora se evaluaría a 9
.
Esta instrucción en Forte se usa tanto para almacenar información como para controlar el flujo (las líneas están numeradas y al cambiar el valor de sus números puede determinar el orden de su ejecución). En este desafío no abordaremos este segundo aspecto.
El reto
Debe escribir un intérprete para un subconjunto simplificado de las LET
expresiones de Forte .
Recibirá como entrada una serie de líneas siguiendo esta gramática:
<line>::= <number>=<expression>
<expression>::= <number>|<expression>+<number>
Nota: esta gramática no es válida Forte porque carece de números de línea, LET y paréntesis (que siempre son obligatorios)
Es decir, solo tendrá que ocuparse de sumar cálculos y asignar valores a los números. Los paréntesis no estarán presentes en la entrada, y cada expresión deberá evaluarse de izquierda a derecha: ¡tenga en cuenta que los resultados parciales se ven afectados por las redefiniciones!
Los números siempre serán enteros no negativos, hasta el límite del tipo de entero nativo de su idioma (o 2 ^ 32, el que sea mayor).
Para cada línea, debe generar el resultado de la expresión y asignar este resultado al valor (posiblemente reasignado) del primer número, lo que afectará la forma en que se interpretarán las siguientes líneas.
Este es el código de golf , ¡el código más corto (en bytes) gana!
Otras reglas
- El formato de entrada es flexible, por ejemplo, puede tomar una sola cadena con nuevas líneas, una lista de cadenas, una lista de listas de números ... Lo mismo ocurre con la salida, siempre que esté claro cuál es el resultado de cada expresión en la entrada
- Puede enviar una función, un programa completo o una solución para que se ejecute en un entorno REPL que lo llame una vez para cada línea.
- Las lagunas estándar están prohibidas, en particular no puede llamar a un intérprete externo de Forte en su código.
Ejemplos
Todos estos son parte de la misma entrada. Después de cada línea, se muestra la salida esperada relativa a esa línea, a veces con un comentario que indica reasignaciones relevantes (que no forman parte de la salida requerida).
5=4
4
6=5
4 # 5 -> 4
7=1+2+5
7
7=5+2+1
4 # Order of operations matters! 5+2 -> 4+2 -> 6 -> 4
18=5+6+7
12
5=3
3 # Remember: 5 -> 4
10=6+4
3 # 6 -> 4 -> 3, 3+3 = 6 -> 3
0
un numero valido?0
es válido ("Los números siempre serán enteros no negativos")Respuestas:
Jalea , 28 bytes
Pruébalo en línea!
Este es uno de los pocos programas de Jelly donde parece ser más terso recibir información de entrada estándar. Es un programa completo (escribir una función habría sido más corto pero está prohibido por las reglas PPCG, porque no se ejecutará correctamente la segunda vez). El formato de entrada se ve así:
Explicación
Función auxiliar
1Ŀ
(traducir un número entero a su valor)De manera conveniente, esta función auxiliar funcionará correctamente en un solo valor o en una lista de valores, debido a la forma en que
y
está definida. Si se proporciona más de una asignación para un solo valor, tomamos la primera asignación de la tabla. La tabla de mapeo se almacena en el registro (que básicamente es solo una variable; Jelly solo tiene una variable).Función auxiliar
2Ŀ
(evaluar una instrucción LET)Realmente no queremos un valor de retorno aquí; solo estamos ejecutando esto por sus efectos secundarios (actualizar el registro y generar el valor asignado). Sin embargo, las funciones Jelly siempre devuelven un valor, por lo que solo dejamos que se devuelva la tabla de mapeo, ya que eso es lo más terso.
Programa principal
Normalmente,
⁸
nos daría el primer argumento de línea de comandos cuando se ejecuta en este contexto, pero no hay ninguno (estamos tomando la entrada de la entrada estándar), por lo que se ejecuta en un modo alternativo que nos da la cadena nula. La necesidad de inicializar el registro (desde su valor predeterminado de0
, que se bloqueay
) significa que no podemos mencionar la entrada del usuario implícitamente, lo que significa que es tan barato tomarlo de la entrada estándar (Ɠ
) como lo sería tomarlo de un argumento de línea de comando (³
o⁸
), y poder acceder al uso alternativo de⁸
significa que la forma de entrada inusual (para Jelly) es en realidad un byte más corto.Es posible que esto sea mejorable. Todavía no he descubierto por qué la segunda línea necesita decir en
⁸Ǥ;
lugar de solo;@Ç
: los dos deberían ser equivalentes, por lo que entiendo a Jelly, dada la falta de uso deµ
/ð
/ø
, pero el último se bloquea por alguna razón. Del mismo modo, hay varias otras formas de reorganizar el programa sin perder bytes, por lo que es posible que haya perdido una forma de hacer las cosas un poco más cortas.Por cierto, cambiar el
ḷ
en la última línea para;
darle una mirada interesante sobre el funcionamiento interno del programa, ya que luego generará el "historial del registro" que está implícitamente emitido por los valores de retorno de2Ḷ
.fuente
Perl 5 , 92 bytes
90 bytes de código +
-pl
banderas.Pruébalo en línea!
Utilizo la tabla hash
%h
para almacenar la asignación entre números.La función (
sub
)f
devuelve el número al que se asigna su entrada (o su entrada si se asigna a ningún número):$h{$a=pop}
recupera el número hacia el cual se asigna la entrada. Si no es ninguno, gracias a//$a
, el valor de($b=$h{$a=pop}//$a)
es input ($a
). Nos aseguramos de que estos valores no sean la entrada en sí misma para que no se repitan infinitamente (!=$a
). Luego, llamamos recursivamentef
o devolvemos la entrada.El programa principal consta de dos pasos:
-
s%(\d+)\+(\d+)%f($1)+f$2%e&&redo
evalúa la primera adición en el lado derecho, mientras todavía hay una adición: reemplazax+y
por el resultado de la evaluación def(x)+f(y)
.-
/=/;$_=$h{f$`}=f$'
hace la tarea:/=/
permite acceder al lado izquierdo con$`
y al lado derecho con$'
, luego$h{f$`}=f$'
realiza la asignación. Y también lo asignamos a$_
eso se imprime implícitamente después de cada línea.fuente
JavaScript (Node.js) , 81 bytes
Pruébalo en línea!
Recibe la entrada llamando a f con el valor a asignar, luego llamando al resultado con una matriz de valores para sumar. (es decir
f(5)([4])
) Repita para varias líneas.v
se usa como una función para calcular el valor actual real de un número, y también como un objeto para almacenar los valores reales. Primerov[x]=v[x]||x
asegura quev[x]
se define.v[x]-x
realiza una comparación para determinar si este es el número real o no. Si el número no se asigna a sí mismo,v(v[x])
vuelve a intentarlo recursivamente; de lo contrario, vuelvex
.f
realiza el cálculo y la asignación, al curry para guardar un byte, donde la segunda llamada devuelve el valor calculado.fuente
Haskell ,
116 113 108106 bytesPruébalo en línea! Cada ecuación
4=3+1+5
se anota como tupla(4,[3,1,5])
. La función anónima(id?)
toma una lista de tales tuplas y devuelve una lista de todos los resultados intermedios.#
es una función para encontrar un punto fijo de una función dadae
y un valor inicialx
.La función
?
toma una función de evaluacióne
y resuelve recursivamente cada ecuación.foldl1(\a b->e#(e#a+e#b))s
evalúa el lado derecho de una ecuación y guarda el resultado enm
, por ejemplo, para4=3+1+5
calculareval(eval(eval 3 + eval 1) + eval 5)
, donde cadaeval
una es una aplicación de punto fijoe
. Luego, la función eval se modifica para tenern
en cuenta la nueva asignación de :(\x->last$m:[e#x|x/=e#n])
que es lo mismo que\x -> if x == eval n then m else eval x
.La función de evaluación inicial es la
id
que asigna cada entero a sí mismo.¡Gracias a Ørjan Johansen por una función de punto de fijación más corta, ahorrando 2 bytes!
fuente
last.
(#)e=until((==)=<<e)e
o(#)=until=<<((==)=<<)
es más cortook, 48 bytes
Uso:
f[5;1 2 3] / 5=1+2+3
Pruébalo en línea!
Si no te importa tener un límite superior a los números que se pueden utilizar, por ejemplo, sólo el uso de números
0
a través de998
, a continuación, las siguientes basta ( 41 bytes ± a pocos dependiendo de la máxima):Explicación:
;
separa tres definicionesa
es un diccionario / mapa de números. En el primer caso, es un diccionario real y vacío[]
, en el segundo caso es una lista de los números0
para998
.s
es una función que encuentra el número "resultante" cuando se le asigna un número. El/
final de la función significa que se aplicará a su propia salida hasta que la salida deje de cambiar.El último bit
f
, significa que:fuente
Python 3,
146132130 bytes14 bytes guardados gracias a @Dada
2 bytes guardados gracias a @ mbomb007
Pruébalo en línea!
Recibe entradas como tuplas de ecuaciones [
x = y + z + w
as(x, (y, z, w))
], salidas a través del generador.fuente
g
Probablemente podría ser escritog=lambda x:d.get(x)and d[x]!=x and g(d[x])or x
. Y creo que puede usar 1 espacio para sangrar en lugar de 2. Eso debería llevarlo a [132 bytes] (¡ Pruébelo en línea! ).