Доведіть 2 + 2 = 2 * 2 (і подібне)


12

Виведіть повний формальний підсумок таких тверджень, як 1+2=3, наприклад , 2+2=2*(1+1)тощо.

Інтродукція

Якщо ви знаєте арифметику піано, ви, ймовірно, можете пропустити цей розділ.

Ось як ми визначаємо натуральні числа:

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

Звідси, наприклад S(S(S(0))), число.

Ви можете використовувати будь-яке еквівалентне представлення у своєму коді. Наприклад, усе це дійсне:

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

Ми можемо розширити правила, щоб визначити додавання наступним чином.

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

Цим ми можемо довести 2 + 2 = 4 наступним чином

         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

Ми можемо розширити ці правила для визначення множення наступним чином

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

Хоча для цього нам потрібно визначити структурну роль дужок.

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

Оператори додавання та множення суворо двійкові, і дужки завжди повинні бути явними. A+B+CНе добре визначені, але (A+B)+Cі A+(B+C)є.

Приклад

Тепер нам достатньо довести теорему про множення: 2 + 2 = 2 * 2

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

Вимоги

Доказ того, щоA=B це список виразів , таких , що:

  • у - перших A,
  • останнє є B, і
  • кожен вираз у списку крім першого може бути отриманий від попереднього шляхом перетворення його за одним із правил.

Ваша програма прийме два дійсних вирази як вхідні дані , кожен вираз містить числа, додавання, множення та дужки, як визначено вище.

Ваша програма видасть доказ, перелік, як визначено вище, що два вирази рівні, якщо такий доказ існує.

Якщо два вирази не рівні, ваша програма нічого не видасть.

Доведення або спростування завжди можливо за допомогою обмеженої кількості кроків, оскільки кожен вираз може бути зведений до одного числа, і ці числа можна тривіально перевірити на рівність.

Якщо вхідні вирази недійсні (наприклад, незбалансовані круглі дужки, містять нечислові чи небінарні оператори), то ваша програма повинна вийти з помилкою, викинути виняток, надрукувати помилку чи іншим чином створити певну поведінку, що спостерігається, що відрізняється від випадок, коли дані є дійсними, але нерівними .

Підсумовуючи, нормальний вихід для допустимих входів - це список рівних чисел, включаючи входи, який складається за наступними правилами.

(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.)

Будь-яке підходяще уявлення чисел в вході і виході допускається, наприклад 0=""=(), 3="###"=(((())))і т.д. Прогалини не має значення.

Правила, звичайно, можна застосовувати в будь-якому напрямку. Вашій програмі не потрібно виводити, яке правило використовується, а лише вираз, отриманий його дією на попередній вираз.

Найкоротший код виграє.


Відповіді:


5

Perl, 166 + 1 байт

Виконати з -p(1 байт).

$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:""

Більш зрозумілі:

                           # неявно: прочитати рядок введення в $ _
                           # залишаємо новий рядок увімкнутим
$ r = '\ ((S *)'; # ми використовуємо цей фрагмент регулярних виразів, визначаємо його
(@b, @a) = @a; # встановити @b на @a, @a - порожнє
натисніть @a, $ _ під час # кожного разу навколо циклу, додайте $ _ до @a
+ s / \ + S / S + / || # правило 2: змінити "+ S" на "S +"
s / $ r \ + \) / $ 1 / || # правило 1: змінити "(X + 0)" на "X"
s / $ r \ * \) // || # правило 3: змінити "(X * 0)" на ""
s / $ r \ * S (S *) / (($ 1 * $ 2) + $ 1 / || # правило 4: зміни "(X * Y" на "((X * Y) + X"
s / $ r \) / $ 1 /; # правило 5: змінити "(X) на" X "
$ \. = / [^ S] ./ s; # додайте 1 до символу нового рядка, якщо ми
                           # бачити будь-який не-S, за яким нічого не йде
$ _ = $ b [-1] eq $ a [-1]? # якщо @b і @a закінчуються однаково
  приєднатися '', @ b, назад @ a #, тоді $ _ стає @b, а потім (@a назад)
  : "" # в іншому випадку порожній $ _
                           # неявно: вихід $ _

Формат введення виражає числа унарними у вигляді рядків Sта вимагає двох входів в окремих рядках (за кожним слідує новий рядок та EOF після того, як вони видно обидва). Я трактував питання як таке, що дужки повинні бути буквально, ( )а додавання / множення - буквально + *; Я можу заощадити кілька байтів за допомогою менш евакуйованих, якщо мені дозволяють робити різні варіанти.

Алгоритм фактично порівнює перший рядок введення з порожнім рядком, другий з першим, третій з другим тощо. Це відповідає вимогам питання. Ось приклад запуску:

Мій внесок:

(SS + SS)
(SS * SS)

Вихід програми:

(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)

Дублювання SSSSв середині дратує, але я вирішив, що це не порушує специфікацію, і це менше байтів, щоб залишити його.

При неправильному введенні я додаю 1символ нового рядка, тож 1у кінці виводу ви отримуєте розсипаються бродячі .


echo -e "((SS+)+(S+S))\nSS*SS" | perl -p /tmp/x.plвиходи 1.
шприц

Це правильно, вам не вистачає дужок у другому рядку (що має говорити (SS*SS)). "Оператори додавання та множення є суто двійковими, і дужки завжди повинні бути явними."
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.