为什么 ((_: Int, _: Int) => _ / _) 当 ((_: Int) / (_: Int)) 不编译?

Jai*_*bhu 3 scala scala-placeholder-syntax

我正在学习 Scala 并且有一个非常基本的问题。考虑使用占位符语法的以下两个表达式 -

// Syntax A  
val fnA = (_: Int, _: Int) => _ / _

// Syntax B
val fnB = (_: Int) / (_: Int) 
Run Code Online (Sandbox Code Playgroud)

以及他们尝试的应用——

// Syntax A
fnA(33, 3)

// Syntax B
fnB(33, 3)
Run Code Online (Sandbox Code Playgroud)

在这两个中,只有 B 和 App(B) 是有效的语法,我不知道为什么。如果编译器能够推断参数(以及应用它们的顺序),fnB为什么它不能为fnA?我的问题是基于fnB一个简写的前提,fnA我很确定这种推理存在缺陷。我只是不确定缺陷是什么。

Mar*_*lic 5

箭头左边下划线的含义 =>

(_: Int, _: Int) => ...
Run Code Online (Sandbox Code Playgroud)

不同的下划线的周围管道符的意思/

(_: Int) / (_: Int) 
Run Code Online (Sandbox Code Playgroud)

前者的意思是

“我们正在定义一个接受两个参数的函数,但是我们不会在函数体中使用这些参数”

而后者是定义两个参数的函数的简写

(x: Int, y: Int) => x / y
Run Code Online (Sandbox Code Playgroud)

例如,

(_: Int, _: Int) => (_: Int) / (_: Int)
Run Code Online (Sandbox Code Playgroud)

脱糖到类似的东西

(a: Int, b: Int) => ((x: Int, y: Int) => x / y)
Run Code Online (Sandbox Code Playgroud)

我们看到参数a并且b没有在 body 中使用,而这恰好是另一个函数((x: Int, y: Int) => x / y)

Daniel将这两种含义记录为

_ + _             // Anonymous function placeholder parameter
_ => 5            // Discarded parameter
Run Code Online (Sandbox Code Playgroud)

作为旁注,考虑在涉及类型构造函数及其边界的类型级别有点类似的情况,其中下划线的含义取决于上下文

CC[_] <: Iterable[_]  
Run Code Online (Sandbox Code Playgroud)

就个人而言,我的思想欺骗我认为它相当于

CC[x] <: Iterable[x]  
Run Code Online (Sandbox Code Playgroud)

但是,这种情况并非如此,并在左边的下划线的意义<:不同的,从右边的意义

CC[x] <: Iterable[y] forSome {type y}
Run Code Online (Sandbox Code Playgroud)

注意 howx没有出现在Iterable[y] forSome {type y}. Adrian 在Common Pitfalls下对此进行了记录:

...也许令人惊讶的CC[_] <: Traversable[_]是,不等于 CC[X] <: Traversable[X]. 前者扩展为CC[X] <: Traversable[T] forSome {type T}, 其中T存在约束,因此与 无关 X

并在对类型构造函数的类型边界注释

比较类型和值的级别,非常不幸的是,类型级别下划线与值级别下划线的行为不同。在价值层面,_ + _确实代表(x, y) => x + y,一个函数。正如我在其他评论中所暗示的,类型级下划线是上下文敏感的,它从不引入类型级函数。它要么是匿名类型参数定义,要么是匿名存在。这些都没有价值级别的等价物。

因此,我们应该谨慎地在其上下文中解释下划线的含义。