为什么 print() 不受运算符优先级的影响?
Why does print() isn't affected by operator precedence?
当我在我的测试中得到一个奇怪的结果时,我正在为 C 设置运算符优先级和结合性 table,对于 Perl 作为先验的同样奇怪的行为。
**
幂运算符是 右结合,这意味着表达式从右到左求值。
它显然可以正确地使用算术表达式,但奇怪的是,它并没有通过 print 函数调用产生预期的结果。
我预计这会输出 321
$ perl -E 'print("1") ** print("2") ** print("3"); say ""'
123
但它产生 123
这也发生在用户定义的函数中:
$ perl -E 'sub my_print { print $_[0] } my_print(1) ** my_print(2) ** my_print(3); say ""'
123
更奇怪,
$ perl -E 'sub my_print { say $_[0]; $_[0] } say my_print(2) ** my_print(2) ** my_print(4);'
2
2
4
65536
当我们定义一个带有 print
副作用的函数时,它也是 return 一个值。算术表达式的结果具有正确的预期值,按运算符关联性定义的顺序进行评估,但 print
仍然违背运算符关联性。
好像有2个求值顺序。
- 正常的评估顺序,由 AST 定义,算法会在它上面进行评估(或者更可能在
man perlguts
和 [=19= 中解释的“评估顺序传递”期间) ]).
- 副作用的第二个评估顺序或 I/O 似乎具有副作用的内置函数调用被放入队列中,这带来了问题:它们按什么顺序放置
我假设这不是一个错误,而是一个功能。如果它是一个错误,它早就被发现了。
所以这带来了我的实际问题:
这种行为的合理性是什么?
和
它是如何实现的?。 (这意味着使用了哪些数据结构以及在哪个编译时间阶段发生了这种情况)。
如果我认为某处存在 AST 级队列是对的,那么 print
调用按哪个顺序排队?
编辑 1:
作为一个额外的精确度,我知道在 I/O 期间涉及队列,但这并没有改变 I/O 操作通常按程序的评估顺序排队的事实,而不是任意的左 -程序文本的右顺序。
您混淆了操作数求值顺序和运算符 precedence/associativity。
运算符结合性决定了 if
X ** Y ** Z // 2 ** 2 ** 3, for example
表示
( X ** Y ) ** Z // ( 2 ** 2 ) ** 3 = 64
或
X ** ( Y ** Z ) // 2 ** ( 2 ** 3 ) = 256
正如你所说,**
是right-associative,所以是后者。
它与 X
、Y
、Z
和 Y ** Z
相对于彼此求值的顺序无关。只要 Y
和 Z
在 Y ** Z
之前求值,无论这四个表达式的计算顺序如何,以上都会产生相同的结果。
可以得出一些结论。如前所述,Y
和 Z
显然需要在 Y ** Z
之前求值。但是没有这样的要求[1],并且文档中没有明确的相反声明[2],运算符可以按顺序求值编译器的选择。
另一个例子是 short-circuiting 运算符必须在 right-hand 副操作数之前评估其 left-hand 副操作数。
逗号运算符保证按顺序计算每个操作数。
当我在我的测试中得到一个奇怪的结果时,我正在为 C 设置运算符优先级和结合性 table,对于 Perl 作为先验的同样奇怪的行为。
**
幂运算符是 右结合,这意味着表达式从右到左求值。
它显然可以正确地使用算术表达式,但奇怪的是,它并没有通过 print 函数调用产生预期的结果。
我预计这会输出 321
$ perl -E 'print("1") ** print("2") ** print("3"); say ""'
123
但它产生 123
这也发生在用户定义的函数中:
$ perl -E 'sub my_print { print $_[0] } my_print(1) ** my_print(2) ** my_print(3); say ""'
123
更奇怪,
$ perl -E 'sub my_print { say $_[0]; $_[0] } say my_print(2) ** my_print(2) ** my_print(4);'
2
2
4
65536
当我们定义一个带有 print
副作用的函数时,它也是 return 一个值。算术表达式的结果具有正确的预期值,按运算符关联性定义的顺序进行评估,但 print
仍然违背运算符关联性。
好像有2个求值顺序。
- 正常的评估顺序,由 AST 定义,算法会在它上面进行评估(或者更可能在
man perlguts
和 [=19= 中解释的“评估顺序传递”期间) ]). - 副作用的第二个评估顺序或 I/O 似乎具有副作用的内置函数调用被放入队列中,这带来了问题:它们按什么顺序放置
我假设这不是一个错误,而是一个功能。如果它是一个错误,它早就被发现了。
所以这带来了我的实际问题: 这种行为的合理性是什么? 和 它是如何实现的?。 (这意味着使用了哪些数据结构以及在哪个编译时间阶段发生了这种情况)。
如果我认为某处存在 AST 级队列是对的,那么 print
调用按哪个顺序排队?
编辑 1: 作为一个额外的精确度,我知道在 I/O 期间涉及队列,但这并没有改变 I/O 操作通常按程序的评估顺序排队的事实,而不是任意的左 -程序文本的右顺序。
您混淆了操作数求值顺序和运算符 precedence/associativity。
运算符结合性决定了 if
X ** Y ** Z // 2 ** 2 ** 3, for example
表示
( X ** Y ) ** Z // ( 2 ** 2 ) ** 3 = 64
或
X ** ( Y ** Z ) // 2 ** ( 2 ** 3 ) = 256
正如你所说,**
是right-associative,所以是后者。
它与 X
、Y
、Z
和 Y ** Z
相对于彼此求值的顺序无关。只要 Y
和 Z
在 Y ** Z
之前求值,无论这四个表达式的计算顺序如何,以上都会产生相同的结果。
可以得出一些结论。如前所述,Y
和 Z
显然需要在 Y ** Z
之前求值。但是没有这样的要求[1],并且文档中没有明确的相反声明[2],运算符可以按顺序求值编译器的选择。
另一个例子是 short-circuiting 运算符必须在 right-hand 副操作数之前评估其 left-hand 副操作数。
逗号运算符保证按顺序计算每个操作数。