Докажите 2 + 2 = 2 * 2 (и аналогичные)

12

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

Introuction

Если вы знаете арифметику Пеано, вы можете пропустить этот раздел.

Вот как мы определяем натуральные числа:

(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="###"=(((())))и т. Д. Пробельные символы не имеют значения.

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

Самый короткий код выигрывает.

spraff
источник

Ответы:

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, $ _ while # каждый раз вокруг цикла, добавляйте $ _ к @a
+ S / \ + S / S + / || # правило 2: измените "+ S" на "S +"
с / $ г \ + \) / $ 1 / || # правило 1: измените "(X + 0)" на "X"
s / $ г \ * \) // || # правило 3: изменить "(X * 0)" на ""
s / $ r \ * S (S *) / (($ 1 * $ 2) + $ 1 / || # правило 4: измените "(X * Y" на "((X * Y) + X")
с / $ г \) / $ 1 /; # правило 5: изменить "(X) на" X "
$ \ = / [^ S] ./ s. # добавить 1 к символу новой строки, если мы
                           # увидеть любой не-S, за которым следует что-нибудь
$ _ = $ Б [-1] экв $ а [-1]? # если @b и @a заканчиваются одинаково
  join '', @ b, reverse @ a #, затем $ _ становится @b, за которым следует (@a назад)
  : "" # иначе пусто $ _
                           # неявный: вывод $ _

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

Алгоритм фактически сравнивает первую строку ввода с пустой строкой, вторую - с первой, третью - со второй и т. Д. Это отвечает требованиям вопроса. Вот пример запуска:

Мой вклад:

(SS + SS)
(СС * СС)

Выход программы:

(ССС + S)
(ГССО +)
SSSS
SSSS
(ГССО +)
((SS +) SS +)
(((СС *) SS +) SS +)
(((СС *) S + S) SS +)
(((СС *) + СС) SS +)
((СС * S), SS +)
((СС * S), S + S)
((СС * S) + СС)

Дублированный SSSSв середине раздражает, но я решил, что это не нарушает спецификации, и меньше байтов, чтобы оставить его.

При неправильном вводе я добавляю 1символ новой строки, так что 1в конце вывода добавляются случайные числа.


источник
echo -e "((SS+)+(S+S))\nSS*SS" | perl -p /tmp/x.plвыходы 1.
spraff
Это верно, вам не хватает скобок во второй строке (что следует сказать (SS*SS)). «Операторы сложения и умножения строго двоичны, а круглые скобки всегда должны быть явными».