要简洁但足够描述性地提出问题是很困难的。我想通过交集操作为
Semigroup
创建一个 Set
实例。因此,我试图与编译器沟通,我希望所有集合都有一个实例,无论其类型参数如何,但组合应该仅适用于相同元素类型的集合。
trait Semigroup[A] {
def combine(x: A, y: A): A
}
object Semigroup {
implicit def setIntersectionSG: Semigroup[Set[_]] = new Semigroup[Set[A]] { //error: not found: type A
def combine(s1: Set[A], s2: Set[A]) = s1.intersect(s2)
}
}
如果我尝试在整个半群定义中使用通配符类型参数,我会得到
type mismatch;
[error] found : Set[_$4] (in scala.collection.immutable)
[error] required: Set[_$3] (in scala.collection)
[error] def combine(s1: Set[_], s2: Set[_]) = s1.intersect(s2)
[error] ^
这在 Scala 2 或 3 中可行吗?如果是,怎么办?如果没有,为什么?
有几种方法可以做到这一点,但没有一个使用存在类型(
Set[_]
):
trait Semigroup[A] {
def combine(x: A, y: A): A
}
object Semigroup {
implicit def setIntersectionSG[A]: Semigroup[Set[A]] = new Semigroup[Set[A] {
def combine(s1: Set[A], s2: Set[A]) = s1.intersect(s2)
}
}
Semigroup
,那么还有SemigroupK
// If F[_] is used as a type parameter, then it's a type constructor instead
// of existential type, Scala 3 allows making a distinction clearer:
// F[_] (type constructor) vs F[?] (existential type)
trait SemigroupK[F[_]] {
def combineK[A](x: F[A], y: F[A]): F[A]
def algebra[A]: Semigroup[F[A]] = combineK(_, _) // Single Abstract Method
}
SemigroupK
对于像集合这样的类型很有用,它们是类型参数的,但无论我们应用哪种类型参数都可以组合。