在 Scala 2 或 3 中,是否有不使用匹配类型的更高种类的参数提取器?

问题描述 投票:0回答:2

这是 Scala 3 中的一个简短示例:

  type Ext[S <: Seq[_]] = S match {
    case Seq[t] => t
  }
  
trait XX[A, B <: Seq[A]]

trait XX1[B <: Seq[_]] extends XX[Ext[B], B]

到目前为止它似乎是有效的,但是当与类型类结合时,面具开始剥落

implicitly[Ext[Seq[Int]] =:= Int] // e.scala: Cannot prove that e.Ext[Seq[Int]] =:= Int

可能是Scala type class & match types兼容性问题导致的。目前,避免这种情况的唯一方法似乎是不使用匹配类型。在 Scala 2 或 Scala 3 中有可能吗?

更新 1:我尝试了以下替代方法:

  type Ext[S] = S match {
    case Seq[t] => t
  } // success!

  type Ext[S <: Any] = S match {
    case Seq[t] => t
  } // success!

  type Ext[S <: Seq[Any]] = S match {
    case Seq[t] => t
  } // same error

所以我相当确定这是一个错误。同样,问题是如何从一开始就避免使用匹配类型?

scala typeclass scala-3 higher-kinded-types match-types
2个回答
1
投票

我在 Scala3 方面没有太多经验,但我猜你要找的是这个:

type Ext[S] = S match {
  case Seq[t] => t
}

你不需要指定

S
是一个
Seq
,因为你不提供其他类型的选择器,你不能在编译时为
Seq
使用除
Ext
以外的其他类型:

implicitly[Ext[Option[String]] =:= String] // compile-time error
// selector Option[String] matches none of the cases

不确定这是否是一个错误,乍一看我是这样的,好吧,你正在匹配

S
(这是一种)与类型(即
Seq[t]
),所以编译器无法证明你。但它仍然可以与种类相匹配:

type Ext[S <: Seq[_]] = S match {
  case Vector[t] => t
  case List[_] => String
}

implicitly[Ext[Vector[Float]] =:= Float]
implicitly[Ext[List[_]] =:= String]

0
投票

看起来像个虫子。

匹配类型的替代方法是类型类

trait ExtTC[S]:
  type Out
object ExtTC:
  type Aux[S, Out0] = ExtTC[S] { type Out = Out0 }

  given [S <: Seq[T], T]: Aux[S, T] = null

val ext = summon[ExtTC[Seq[Int]]]
summon[ext.Out =:= Int] // compiles

这对类型推断没有帮助

trait XX[A, B <: Seq[A]]

// doesn't compile: Type argument B does not conform to upper bound Seq[XX1.this.ext.Out]
trait XX1[B <: Seq[_]](using val ext: ExtTC[B]) extends XX[ext.Out, B] 

但可以帮助隐式解决

trait XX[A, B](using B <:< Seq[A])

trait XX1[B <: Seq[_]](using val ext: ExtTC[B]) extends XX[ext.Out, B] // compiles
© www.soinside.com 2019 - 2024. All rights reserved.