gpt4 book ai didi

function - Scala 中具有重载方法的方法和函数之间的 Eta 扩展

转载 作者:行者123 更新时间:2023-12-02 10:11:33 24 4
gpt4 key购买 nike

我想了解为什么 eta 扩展(§6.26.5)不适用于重载方法。例如,如果我有以下两种方法:

def d1(a: Int, b: Int) {}
def r[A, B](delegate: (A, B) ⇒ Unit) {}

我可以做到这一点:

r(d1)

但是,当重载r时,它将不再起作用:

def r[A, B](delegate: (A, B) ⇒ Unit) {}
def r[A, B, C](delegate: (A, B, C) ⇒ Unit) {}

r(d1) // no longer compiles

我必须显式地将方法转换为部分应用的函数:

r(d1 _)

有没有办法通过显式转换来完成以下操作?

def r[A, B](delegate: (A, B) ⇒ Unit) {}
def r[A, B, C](delegate: (A, B, C) ⇒ Unit) {}

def d1(a: Int, b: Int) {}
def d2(a: Int, b: Int, c: Int) {}

r(d1) // only compiles with r(d1 _)
r(d2) // only compiles with r(d2 _)

有一些类似的question ,但没有完全解释。

最佳答案

“隐式”是正确的术语,该部分是规范中的 6.26.2,这一定是一个重复的问题(或者人们会这么认为;这是稳定的行为)。

链接的问题还回答了预期类型必须是函数。

我会大胆地说,当重载时,适用性会受到损害,因为没有预期的类型(6.26.3,臭名昭著)。当不重载时,6.26.2 适用(eta 扩展),因为参数的类型决定了预期的类型。重载时,arg 是专门指定的,没有预期的类型,因此 6.26.2 不适用;因此 d 的重载变体均不被视为适用。

From 6.26.3 Overloading Resolution

Otherwise, let S 1 , . . . , S m be the vector of types obtained by typing each argument with an undefined expected type.

以下是当您命名不带参数的方法时可用的“隐式转换”(所谓的),如 r(d1) 中所示。关于 eta 扩展的段落适用于此处。

6.26.2 Method Conversions

The following four implicit conversions can be applied to methods which are not applied to some argument list.

Evaluation. A parameterless method m of type => T is always converted to type T by evaluating the expression to which m is bound.

Implicit Application. If the method takes only implicit parameters, implicit argu- ments are passed following the rules of §7.2.

Eta Expansion. Otherwise, if the method is not a constructor, and the expected type pt is a function type (Ts ) ⇒ T , eta-expansion (§6.26.5) is performed on the expression e.

Empty Application. Otherwise, if e has method type ()T , it is implicitly applied to the empty argument list, yielding e()

更多绿色检查后解释...

以下示例演示了在存在重载的情况下优先应用应用程序而不是 eta 扩展。当 eta 扩展不适用时,“空应用程序”是第 6.26.2 节中要尝试的最终隐式。换句话说,当重载时(表面上看这已经够困惑和邪恶的了),根据统一访问原则,很自然地将 f 视为 f(),但将 f 视为 f _ 是不自然或奇怪的,除非您非常确定需要函数类型。

scala> object Bar {
| def r(f: () => Int) = 1
| def r(i: Int) = 2
| }
defined module Bar

scala> def f() = 4
f: ()Int

scala> Bar.r(f)
res4: Int = 2

scala> Bar.r(f _)
res5: Int = 1

重载决议的候选者通过“形状”进行预先筛选。形状测试封装了这样的直觉:eta 扩展从未被使用,因为 args 的类型没有预期的类型。此示例表明,即使 eta 扩展是“表达式进行类型检查的唯一方法”,也不会使用它。

scala> object Bar {
| def bar(f: () => Int) = 1
| def bar(is: Array[Int]) = 2
| }
defined object Bar

scala> def m() = 7
m: ()Int

scala> m _
res0: () => Int = <function0>

scala> Bar.bar(m)
<console>:10: error: overloaded method value bar with alternatives:
(is: Array[Int])Int <and>
(f: () => Int)Int
cannot be applied to (Int)
Bar.bar(m)
^

读到这里的任何人都会对a related issue with these two conversions感到好奇。 .

关于function - Scala 中具有重载方法的方法和函数之间的 Eta 扩展,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17324247/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com