微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

[F <: List[A], A] 和 [F[_] <: List[A], A] 之间的推理差异

如何解决[F <: List[A], A] 和 [F[_] <: List[A], A] 之间的推理差异

考虑以下两个类型参数子句中类型参数A推断类型构造函数的区别

$ scala3-repl
scala> def f[F <: List[A],A](as: F) = as
def f[F <: List[A],A](as: F): F

scala> f(List(42))
val res0: List[Int] = List(42)

scala> def f[F[_] <: List[A],A](as: F[A]) = as
def f[F[_$1] <: List[A],A](as: F[A]): F[A]

scala> f(List(42))
val res1: List[Any] = List(42)

为什么在第二种情况下,类型构造函数 A 的类型参数 F 被推断为 Any

解决方法

根据我对您在第二种情况下的定义的解释,F[_]List 类型构造函数,但 List[A] 必须是任何列表 F[_] 的上限可以构造,所以 A 必须是 Any

可能你想要的是这个:

def f[F[_] <: List[_],A](as: F[A]) = as

def f[F[x] <: List[x],A](as: F[A]) = as

特别适用于需要将 x 固定为多个约束参数的情况(示例请参考下方@user 评论)

在第一种情况下,F 是具体类型,因此 List[A] 不是所有列表的上限,而是仅在列表 F 上,因此 A 不是'不必是 Any,最窄的可推断类型是 Int

,

不是一个完整的答案,只是一些思考:我试图构建一个反例,但在假设 {{1} } 将被推断为最窄的类型。不过,也许你会觉得它很有趣。

这是一个具有类似约束的函数 A,但我们采用了略有不同的类型构造函数来代替 h

主要思想是 List 有两个独立的类型参数:

  • 第一个是Cc中的_
  • 第二个是在 F[_] 约束中与 A 交互的那个

请注意,如果 <: Lst[A] 被推断为最窄的类型 (A),则不会编译:

Nothing

如果 (run in 3.0.0-RC2) scala> trait Lst[+X] // defined trait Lst scala> case class Cc[+I,+X](i: I) extends Lst[X] // defined case class Cc scala> type T[+I] = Cc[I,Nothing] // defined alias type T[+I] = Cc[I,Nothing] scala> def h[F[_] <: Lst[A],A](as: F[A]) = as def h[F[_$1] <: Lst[A],A](as: F[A]): F[A] scala> val xs: T[Int] = Cc(42) val xs: T[Int] = Cc(42) scala> h(xs) val res9: Cc[Int,Nothing] = Cc(42) 被推断为满足 A 约束的最窄可能类型,那么 <: Lst[A] 将是 A,并且参数必须是类型 { {1}},无人居住。

我认为这很有趣,但我不明白为什么如果不编译它实际上会很糟糕。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。