如果存在子类型,Scala中存在的用例有哪些?

时间:2017-05-05 14:34:10

标签: scala haskell existential-type subtyping

如果Scala还有子类型,Scala中存在存在性是否有任何有意义的原因?

例如,在Haskell中,existentials可用于异构lists,但在Scala中,异构列表只需使用子类型即可创建。

这让我想知道如果Scala中存在子类型,为什么有人会想要使用存在?是否有任何用于存在的用例,通过子类型无法更方便地解决?我不确定有没有。任何反例?

编辑:存在对于定义更高级的类型(Functor,Monad等)非常有用,我理解,但除此之外,还有其他有意义的用例吗?

3 个答案:

答案 0 :(得分:2)

我工作项目中存在的例子:

实施类型安全参数存储

trait Parameter[T] // T is a type of a value related to this parameter

trait ParameterStorage {
   def getValue[T](p: Parameter[T]): Option[T]
}

//implementation
type ParamAndValue = (Parameter[T], T) forSome { type T; }

//initialize storage with pairs of parameters and values
class StorageImpl(pairs: ParamAndValue*) { 
   ...
}

答案 1 :(得分:1)

考虑例如Array[_]。它与Array[Any]完全相同,例如

val x: Array[Any] = new Array[Any](5)
x(0) = "" // legal
val y: Array[_] = new Array[Double](5)
y(0) = "" // illegal
  编辑:存在对于定义更高级的类型(Functor,Monad等)非常有用,我理解,但除此之外,还有其他有意义的用例吗?

没有。 F[_] 中的Functor[F[_]]看起来与存在主义相同,但根本不是。

答案 2 :(得分:0)

这是刚才出现的一个例子:

object Test{
  trait Entity
  case class SEntity() extends Entity
  case class RefVal[T<:Entity](a:T)
  def g(o:RefVal[Entity])= ???
  def g2(o:RefVal[_<:Entity])= ???
  g(RefVal[SEntity](a=SEntity())) // does not compile
  g2(RefVal[SEntity](a=SEntity())) // does compile

}

如果我想避免使RefVal协变,那么我需要在这里使用存在感。

换句话说,存在性可用于在更精细的分辨率中设置协方差,例如在上面显示的方法级别上,而不是通过将其声明为RefVal[+T<:Entity]来全局设置RefVal协变。

EDIT2:

以下是存在感的其他一些有用用法:

object Existentials_List extends App {

  class A[T]

  class J

  class C1() extends J

  class C2() extends J

  class Z

  val l: Set[A[_ <: J]] = Set()

  val l2: Set[A[_ <: J]] = l + new A[J]   
  val l3: Set[A[_ <: J]] = l + new A[C1]   
  val l4: Set[A[_ <: J]] = l + new A[Z] // does not compile

}

其他可能性是class A[+T]而只做Set[A[J]]但是这可能会使很多事情变得混乱,协变+注释可以感染大部分代码,其中没有那些协变的东西很重要。因此,保持事物不变并在一个地方(在存储对象的集合中)使用存在性可能比使用协方差注释乱丢代码更简单。