gpt4 book ai didi

scala - 尽管没有应用隐式转换,但仅存在隐式转换就可以使程序编译

转载 作者:行者123 更新时间:2023-12-03 15:40:42 24 4
gpt4 key购买 nike

考虑由类型构造函数f和适当的F[_]类型化的方法A

def f[F[_], A](v: F[A]) = v

让我们尝试将其应用于 new Bar
scala> class Bar
class Bar

scala> def f[F[_], A](v: F[A]) = v
def f[F[_], A](v: F[A]): F[A]

scala> f(new Bar)
^
error: no type parameters for method f: (v: F[A]): F[A] exist so that it can be applied to arguments (Bar)
--- because ---
argument expression's type is not compatible with formal parameter type;
found : Bar
required: ?F[?A]
^
error: type mismatch;
found : Bar
required: F[A]

像预期的那样,此错误是 Bar的形状不正确。

现在让我们添加一个从 BarList[Int]的隐式转换
scala> implicit def barToList(b: Bar): List[Int] = List(42)
def barToList(b: Bar): List[Int]

scala> f(new Bar)
val res1: Any = Bar@56881196

这可以编译,但是请注意,实际上似乎没有应用隐式转换,因为 res1的运行时类是 Bar而不是 List。此外, res1的编译时类型为 Any而不是 List[Int]。查看 -Xprint:typer的输出,我们看到类似
val res1: Any = f[Any, Nothing](new Bar())

我们看到以下推断发生的地方
F[_] = Any
A = Nothing

相对于
F[_] = List
A = Int

而且我们发现实际上没有发生任何转化,也就是说,我们没有看到类似
f(barToList(new Bar()))

为什么仅存在隐式转换会导致程序编译,而实际上未应用任何隐式转换?请注意,当明确说明类型参数时,它会按预期工作
scala> f[List, Int](new Bar)
val res2: List[Int] = List(42)

最佳答案

我之前已经注意到了这个问题,并且我认为可以在编译器中将其追溯到this code:

  // Then define remaining type variables from argument types.
foreach2(argtpes, formals) { (argtpe, formal) =>
val tp1 = argtpe.deconst.instantiateTypeParams(tparams, tvars)
val pt1 = formal.instantiateTypeParams(tparams, tvars)

// Note that isCompatible side-effects: subtype checks involving typevars
// are recorded in the typevar's bounds (see TypeConstraint)
if (!isCompatible(tp1, pt1)) {
throw new DeferredNoInstance(() =>
"argument expression's type is not compatible with formal parameter type" + foundReqMsg(tp1, pt1))
}
}
val targs = solvedTypes(tvars, tparams, varianceInTypes(formals), upper = false, lubDepth(formals) max lubDepth(argtpes))

据我了解,问题在于 isCompatible检查查找隐式转换,但没有跟踪是否需要进行转换,而 solvedType仅查看边界。

因此,如果您没有隐式转换,则 isCompatible(Bar, F[A])为false,并且 methTypeArgs调用将引发 DeferredNoInstance异常-它甚至都不会考虑将 Any作为 F的候选对象。

如果您确实进行了隐式转换,则 isCompatible(Bar, F[A])为true,但编译器会立即忘记仅因隐式转换而将其为true,而 solvedTypesAny选择 F,这是因为Scala奇怪的 Any特殊情况下的种多态性。那时, Bar值是完美的,因为它是 Any,并且编译器不会应用在 isCompatible中找到的转换(它忘记了所需的转换)。

(作为附带说明,如果您为 f提供显式类型参数,则根本不会调用 methTypeArgs,并且 isCompatiblesolvedTypes之间的这种差异无关紧要。)

我认为这一定是编译器中的错误。我不知道是否有人已经举报了(我只是花了五分钟时间才看到,却没有看到)。

关于scala - 尽管没有应用隐式转换,但仅存在隐式转换就可以使程序编译,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62415172/

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