证明2 + 2 = 2 * 2(和类似的)


12

输出此类陈述的完整正式形式,例如1+2=32+2=2*(1+1)等。

介入

如果您知道Peano Arithmetic,则可以跳过本节。

这是我们定义自然数的方法:

(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)+CA+(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,和
  • 列表中除第一个表达式外的每个表达式都可以通过根据其中一个规则进行转换而从前一个表达式中获得。

您的程序将使用两个有效表达式作为input,每个表达式均包含数字,加法,乘法和括号(如上定义)。

如果存在这样的证明,您的程序将输出证明,即上述定义的列表,两个表达式相等。

如果两个表达式不相等,则程序将不输出任何内容。

证明或反证总是可以在有限数量的步骤中进行的,因为每个表达式都可以简化为一个数字,并且可以对这些数字进行简单的相等性测试。

如果输入表达式无效(例如,不平衡的括号,包含非数字或非二进制运算符),则您的程序应退出并出现错误,引发异常,打印错误或以其他方式产生可观察到的与输入有效但不相等的情况

总而言之,可接受输入的正常输出是一个由下列规则产生的等号列表,包括输入。

(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="###"=(((())))等空白是无关紧要的。

当然,规则可以在任一方向上应用。您的程序不必输出使用哪个规则,只需输出由其对前一个表达式的操作所产生的表达式。

最短的代码获胜。


Answers:


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以相同的方式结束
  join'',@ b,reverse @ 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
spraff's

没错,您在第二行缺少了括号(应该说(SS*SS))。“加法和乘法运算符严格是二进制的,并且括号必须始终是明确的。”
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.