Probar 2 + 2 = 2 * 2 (y similar)

12

Produzca una poof formal completa de declaraciones tales como 1+2=3, 2+2=2*(1+1)etc.

Introuction

Si conoce la aritmética de Peano, probablemente puede saltear esta sección.

Así es como definimos los números naturales:

(Axiom 1) 0 is a number
(Axiom 2) If `x` is a number, the `S(x)`, the successor of `x`, is a number.

Por lo tanto, por ejemplo, S(S(S(0)))es un número.

Puede usar cualquier representación equivalente en su código. Por ejemplo, todos estos son válidos:

0    ""    0           ()       !
1    "#"   S(0)        (())     !'
2    "##"  S(S(0))     ((()))   !''
3    "###" S(S(S(0)))  (((()))) !'''
...
etc

Podemos extender las reglas para definir la suma de la siguiente manera.

(Rule 1) X+0 = X
(Rule 2) X+S(Y)=S(X)+Y

Con esto podemos probar 2 + 2 = 4 de la siguiente manera

         S(S(0)) + S(S(0)) = 2 + 2
[Rule 2 with X=S(S(0)), Y=S(0)]
         S(S(S(0))) + S(0) = 3 + 1
[Rule 2 with X=S(S(S(0))), Y=0]
         S(S(S(S(0)))) + 0 = 4 + 0
[Rule 1 with X=S(S(S(S(0))))
         S(S(S(S(0))))     = 4

Podemos extender estas reglas para definir la multiplicación de la siguiente manera

(Rule 3) X*0 = 0
(Rule 4) X*S(Y) = (X*Y) + X

Aunque para permitir esto necesitamos definir el papel estructural de los paréntesis.

(Axiom 3) If X is a number, (X) is the same number.

Los operadores de suma y multiplicación son estrictamente binarios y los paréntesis siempre deben ser explícitos. A+B+Cno está bien definido, pero (A+B)+Cy A+(B+C)son.

Ejemplo

Ahora tenemos suficiente para demostrar un teorema sobre la multiplicación: 2 + 2 = 2 * 2

2 + 2
(2) + 2
(0 + 2) + 2
((0*2) + 2) + 2
(1*2) + 2
2*2

Requisitos

Una prueba de queA=B es una lista de expresiones tales que:

  • el primero es A,
  • el último es B, y
  • cada expresión en la lista, aparte de la primera, puede obtenerse de la anterior transformándola bajo una de las reglas.

Su programa tomará dos expresiones válidas como entrada , cada expresión contiene números, suma, multiplicación y paréntesis como se definió anteriormente.

Su programa generará una prueba, una lista como se definió anteriormente, que las dos expresiones son iguales, si tal prueba existe.

Si las dos expresiones no son iguales, su programa no generará nada.

Probar o refutar siempre es posible en un número finito de pasos, porque cada expresión se puede reducir a un solo número y estos números se pueden probar trivialmente para determinar la igualdad.

Si las expresiones de entrada no son válidas (por ejemplo, paréntesis desequilibrados, contienen operadores que no son números u operadores no binarios), entonces su programa debería salir con error, lanzar una excepción, imprimir un error o producir algún comportamiento observable que sea distinto del caso en el que las entradas son válidas pero no iguales .

En resumen, la salida normal para entradas admisibles es una lista de números iguales, incluidas las entradas, que se produce mediante las siguientes reglas.

(Axiom 1) 0 is a number
(Axiom 2) If `x` is a number, the `S(x)`, the successor of `x`, is a number.
(Axiom 3) If X is a number, (X) is the same number

(Rule 1) X+0 = X
(Rule 2) X+S(Y)=S(X)+Y
(Rule 3) X*0 = 0
(Rule 4) X*S(Y) = (X*Y) + X
(Rule 5) X = (X)              (Axiom 3 expressed as a transformation rule.)

Se permite cualquier representación adecuada de los números en la entrada y la salida, por ejemplo 0=""=(), 3="###"=(((()))), etc. espacio en blanco es irrelevante.

Las reglas pueden, por supuesto, aplicarse en cualquier dirección. Su programa no tiene que mostrar qué regla se usa, solo la expresión producida por su acción en la expresión anterior.

El código más corto gana.

rociar
fuente

Respuestas:

5

Perl, 166 + 1 bytes

Corre con -p(penalización de 1 byte).

$r='\((S*)';(@b,@a)=@a;push@a,$_ while+s/\+S/S+/||s/$r\+\)/$1/||s/$r\*\)//||s/$r\*S(S*)/(($1*$2)+$1/||s/$r\)/$1/;$\.=/[^S]./s;$_=$b[-1]eq$a[-1]?join'',@b,reverse@a:""

Más legible:

                           # implícito: leer una línea de entrada en $ _
                           # dejamos la nueva línea en
$ r = '\ ((S *)'; # usamos mucho este fragmento de expresiones regulares, lo factorizamos
(@b, @a) = @a; # establece @b en @a, @a para vaciar
presione @a, $ _ mientras # cada vez que se dé la vuelta al ciclo, agregue $ _ a @a
+ s / \ + S / S + / || # regla 2: cambie "+ S" a "S +"
s / $ r \ + \) / $ 1 / || # regla 1: cambie "(X + 0)" a "X"
s / $ r \ * \) // || # regla 3: cambie "(X * 0)" a ""
s / $ r \ * S (S *) / (($ 1 * $ 2) + $ 1 / || # regla 4: cambie "(X * Y" a "((X * Y) + X"
s / $ r \) / $ 1 /; # regla 5: cambie "(X) a" X "
$ \. = / [^ S] ./ s; # agregue un 1 al carácter de nueva línea si
                           # ver cualquier no S seguido de cualquier cosa
$ _ = $ b [-1] eq $ a [-1]? # si @b y @a terminan de la misma manera
  unirse '', @ b, invertir @ a # luego $ _ se convierte en @b seguido de (@a al revés)
  : "" # de lo contrario está vacío $ _
                           # implícito: salida $ _

El formato de entrada expresa números en unario como cadenas de S, y requiere las dos entradas en líneas separadas (cada una seguida de una nueva línea y un EOF después de que se vean ambas). Interpreté la pregunta como que requiere que los paréntesis sean literalmente ( )y que la suma / multiplicación sea literal + *; Puedo guardar algunos bytes con menos escape si se me permite hacer diferentes elecciones.

El algoritmo en realidad compara la primera línea de entrada con una línea vacía, la segunda con la primera, la tercera con la segunda, y así sucesivamente. Esto cumple con los requisitos de la pregunta. Aquí hay un ejemplo de ejecución:

Mi entrada:

(SS + SS)
(SS * SS)

Salida del programa:

(SSS + S)
(SSSS +)
SSSS
SSSS
(SSSS +)
((SS +) SS +)
(((SS *) SS +) SS +)
(((SS *) S + S) SS +)
(((SS *) + SS) SS +)
((SS * S) SS +)
((SS * S) S + S)
((SS * S) + SS)

El duplicado SSSSen el medio es molesto, pero decidí que no violaba la especificación, y tiene menos bytes para dejarlo.

En una entrada no válida, agrego 1al carácter de nueva línea, por lo que se extravían 1al final de la salida.


fuente
echo -e "((SS+)+(S+S))\nSS*SS" | perl -p /tmp/x.plsalidas 1.
pulverización
Eso es correcto, te faltan los corchetes en la segunda línea (que debería decir (SS*SS)). "Los operadores de suma y multiplicación son estrictamente binarios y los paréntesis siempre deben ser explícitos".