为什么+函数似乎在元组上起作用? [英] Why does the + function appear to work on tuples?
问题描述
在两个Int64的元组上使用+函数将返回总和:
julia> +((1, 2))
3
但是,在引用元组的变量上使用+函数会产生以下错误:
julia> a = (1, 2)
(1,2)
julia> +(a)
ERROR: MethodError: no method matching +(::Tuple{Int64, Int64})
我无法理解为什么会这样,尤其是当以下代码返回true时.
julia> typeof(a) == typeof((1, 2))
请注意,与您的想法相反,
julia> :(+((1, 2)))
:(1 + 2)
这是等效于(+)(1, 2)
的单个函数调用.没有元组,尽管语法看起来像是一个元组. (如您所述,+
函数在元组上不起作用.)这种行为是否合乎需要?好吧,据报道它是一个错误#12755 ,但随后已修复.但是此修复程序导致错误#12771 ,导致该修复程序由拉#12772 .
解决此问题的方法是避免在不显式编写括号的情况下将运算符作为函数调用.即,始终写入(+)(1, 2)
而不是+(1, 2)
.您可以验证(+)((1, 2))
会引发您期望的错误.
(仅一元运算符会出现此问题,因此为什么|
和*
不受此约束.)
如果您有兴趣,此问题的核心是+(x, y)
函数调用语法和一元运算符语法之间的根本歧义.在某些情况下,即使将(
和-
后面跟着(
,也可以将它们解析为一元运算符:
- 在
-(x+y)^2
中,很有可能是(-)((x+y)^2)
的意思,而不是((-)(x+y))^2
.因此,我们不能简单地无条件地将-(
解析为函数调用. - 相反,必须要做的是将
-
解析为特定优先级之后的操作,以便将-x * y
解析为(-x) * y
,将-x + y
解析为(-x) + y
,而将-x^y
解析为-(x^y)
. - 异常:但这会使
-(1, 2)
解析为(-)((1, 2))
,即在元组上调用的函数.无论出于何种原因,决定在-
之后的内容看起来像函数调用元组时添加一个例外.这样可以使+(1, 2)
起作用,但这实际上只是一个hack. - 但是从解析器的角度来看,
((1, 2))
看起来与(1, 2)
完全相同;只是前者用括号括起来.
我个人认为-(1, 2)
表示法很愚蠢(并且并非在所有情况下都有效;例如,在-(1, 2)^2
中).如果没有出现该异常,并且-(1, 2)
始终被解析为对元组的一元函数调用,则可以具有更大的一致性,而不会(我认为)有很多损失.在需要二进制函数调用时只写1 - 2
或(-)(1, 2)
并不太坏.
Using the + function on a tuple of two Int64s returns the sum:
julia> +((1, 2))
3
However, using the + function on a variable that references a tuple gives the following error:
julia> a = (1, 2)
(1,2)
julia> +(a)
ERROR: MethodError: no method matching +(::Tuple{Int64, Int64})
I'm having trouble understanding why it behaves like this, especially when the following code returns true.
julia> typeof(a) == typeof((1, 2))
Note that, contrary to what you might think,
julia> :(+((1, 2)))
:(1 + 2)
This is a single function call equivalent to (+)(1, 2)
. There is no tuple, although the syntax may look like there is a tuple. (The +
function, as you noted, does not work on tuples.) Is this behavior desirable? Well it was reported as a bug #12755, but then fixed. But the fix caused bug #12771 which resulted in the fix being reverted by pull #12772.
The solution to this mess is to avoid calling operators as functions without explicitly writing parentheses. That is, always write (+)(1, 2)
instead of +(1, 2)
. You can verify that (+)((1, 2))
throws the error that you expect.
(This problem only occurs with unary operators, hence why |
and *
are not subject to it.)
If you're interested, the heart of this problem is a fundamental ambiguity between +(x, y)
function call syntax and unary operator syntax. Here are a few situations that motivate parsing +
and -
as unary operators, even when followed by (
:
- In
-(x+y)^2
, it is highly likely that(-)((x+y)^2)
was meant, not((-)(x+y))^2
. So we cannot simply unconditionally parse-(
as a function call. - Instead what must be done is the thing after
-
parsed up to a certain precedence, so that-x * y
is parsed as(-x) * y
,-x + y
as(-x) + y
, but-x^y
as-(x^y)
. - Exception: But this would make
-(1, 2)
parse as(-)((1, 2))
, that is, a function called on a tuple. For whatever reason or another, it was decided to add an exception for when the thing after-
looks like a function call tuple. This is so that+(1, 2)
would work, but this is really mostly just a hack. - But from the parser's perspective,
((1, 2))
looks exactly like(1, 2)
; just the former is wrapped in parentheses.
My personal opinion is that the -(1, 2)
notation is silly (and doesn't work in all cases anyway; e.g. in -(1, 2)^2
). If that exception weren't around, and -(1, 2)
consistently parsed as a unary function call on a tuple, then more consistency could be had without (I think) much loss. It's not too bad to just write 1 - 2
or (-)(1, 2)
when a binary function call is desired.
这篇关于为什么+函数似乎在元组上起作用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!