Scala中的Existensic类型 [英] Existensial types in Scala

查看:144
本文介绍了Scala中的Existensic类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



这对我有用:

  def valueOf(c:Class [_],name:String){
type C = Class [T] forSome {type T <:Enum [T]}
Enum.valueOf(c .asInstanceOf [C],name)
}

但这不是:

  def valueOf(c:Class [_],name:String){
type T = T forSome {type T< :Enum [T]}
Enum.valueOf(c.asInstanceOf [Class [T]],name)
}

在我看来,两个表达式相当于:

  Enum.valueOf(z.asInstanceOf [Class] [T] forSome {type T<:Enum [T]},name)

但是Scala说这只是在我心中:

 推断类型参数[T]不符合方法valueOf的类型参数bounds [ T<:Enum [T]] 
Enum.valueOf(c.asInstanceOf [Class [T]],name)
^


 枚举值(x2) .asInstanceOf [类[X] forSome {类型X <:枚举[X]}],名称)

And:

  Enum.valueOf(x.asInstanceOf [Class [X forSome {type X<:Enum [X] }]],name)

现在考虑类型参数 T valueOf 将在每种情况下被推断。在第一种情况下,我们得到一个 X ,我们知道它们是 Enum [X] 的子类型,我们都设定了在第二种情况下,另一方面, T 将必须是 X forSome {类型X <:枚举[X]} ,关键是这种类型不是枚举的类型[X forSome {type X <:Enum [X]}] ,所以我们不满意对 T 的限制。



问题是你的第二个例子相当于后者。




作为脚注,如果枚举在其中是协整的类型参数。采取以下简化示例:

  trait Foo [A] 
trait Bar [A]

def foo [A< ;: Bar [A]](f:Foo [A])= f

def x:Foo [X] forSome {type X< ;: Bar [X] } = ???
def y:Foo [Y forSome {type Y <:Bar [Y]}] = ???

现在 foo(x)将编译,但是,与您的代码一样, foo(y)不会。但是更改 Bar 有点:

  trait Foo [A] 
trait Bar [+ A]

def foo [A< ;: Bar [A]](f:Foo [A])= f

def x:Foo [X] forSome {type X <:Bar [X]} = ???
def y:Foo [Y forSome {type Y <:Bar [Y]}] = ???

现在他们都会编译。我猜想这与我们对你的两个例子相当的强烈直觉的原因有关。






作为另一个脚注(作为回应 gzmo comment below ),请考虑以下内容:

 阶> trait Foo [A< ;: Foo [A]] 
定义特征Foo

scala> MyFoo类扩展Foo [MyFoo]
定义类MyFoo

scala> val myFoo = new MyFoo
myFoo:MyFoo = MyFoo @ 3ee536d

scala> myFoo:(X forSome {Type X< ;: Foo [X]})
res0:X forSome {type X< ;: Foo [X]} = MyFoo @ 3ee536d

scala> myFoo:Foo [MyFoo]
res1:Foo [MyFoo] = MyFoo @ 3ee536d

假设 X forSome {type X <:Foo [X]} 类型X <:Foo [X]}] (稍后忽略后者甚至不是有效类型的事实)。然后我们可以写下列内容:

  myFoo:Foo [X forSome {type X< ;: Foo [X ]}] 

但是 Foo 是不变的,所以如果我们有一些东西是 Foo [A] Foo [B] 的实例,那么它必须情况是 A =:= B 。但是绝对不是这样的情况: MyFoo =:=(X forSome {type X< ;:Foo [X]})。不确定所有这些都不那么令人困惑,但这是怎么说服自己,编译器知道它在做什么。


Little confusing about existential types.

This works for me:

def valueOf(c: Class[_], name: String) {
  type C = Class[T] forSome {type T <: Enum[T]}
  Enum.valueOf(c.asInstanceOf[C], name)
} 

but this does not:

def valueOf(c: Class[_], name: String) {
  type T = T forSome {type T <: Enum[T]}
  Enum.valueOf(c.asInstanceOf[Class[T]], name)
}

In my mind both expressions are equivalent to:

Enum.valueOf(z.asInstanceOf[Class[T] forSome {type T <: Enum[T]}], name)

But Scala says that it's in my mind only:

inferred type arguments [T] do not conform to method valueOf's type parameter bounds [T <: Enum[T]]
         Enum.valueOf(c.asInstanceOf[Class[T]], name)
              ^

解决方案

Consider the difference between the following two expressions:

Enum.valueOf(x.asInstanceOf[Class[X] forSome { type X <: Enum[X] }], name)

And:

Enum.valueOf(x.asInstanceOf[Class[X forSome { type X <: Enum[X] }]], name)

Now think about how the type parameter T of valueOf will be inferred in each of these cases. In the first case, we've got an X that we know is a subtype of Enum[X], and we're all set. In the second case, on the other hand, T would have to be X forSome { type X <: Enum[X] }, and crucially this type is not a subtype of Enum[X forSome { type X <: Enum[X] }], so we haven't satisfied the constraint on T.

The problem is that your second example is equivalent to the latter.


As a footnote, this would work just fine if Enum were covariant in its type parameter. Take the following simplified example:

trait Foo[A]
trait Bar[A]

def foo[A <: Bar[A]](f: Foo[A]) = f

def x: Foo[X] forSome { type X <: Bar[X] } = ???
def y: Foo[Y forSome { type Y <: Bar[Y] }] = ???

Now foo(x) will compile, but foo(y) won't, just as in your code. But change Bar a bit:

trait Foo[A]
trait Bar[+A]

def foo[A <: Bar[A]](f: Foo[A]) = f

def x: Foo[X] forSome { type X <: Bar[X] } = ???
def y: Foo[Y forSome { type Y <: Bar[Y] }] = ???

Now they'll both compile. I'd guess that this has something to do with the reason that we have such strong intuitions about your two examples being equivalent.


As another footnote (in response to gzmo's comment below), consider the following:

scala> trait Foo[A <: Foo[A]]
defined trait Foo

scala> class MyFoo extends Foo[MyFoo]
defined class MyFoo

scala> val myFoo = new MyFoo
myFoo: MyFoo = MyFoo@3ee536d

scala> myFoo: (X forSome { type X <: Foo[X] })
res0: X forSome { type X <: Foo[X] } = MyFoo@3ee536d

scala> myFoo: Foo[MyFoo]
res1: Foo[MyFoo] = MyFoo@3ee536d

Let's suppose that X forSome { type X <: Foo[X] } were a subtype of Foo[X forSome { type X <: Foo[X] }] (ignoring for a moment the fact that the latter isn't even a valid type). Then we'd be able to write the following:

myFoo: Foo[X forSome { type X <: Foo[X] }]

But Foo is invariant, so if we have some thing that's an instance of both Foo[A] and Foo[B], then it must be the case that A =:= B. But it's definitely not the case that MyFoo =:= (X forSome { type X <: Foo[X] }). Not sure all of that is any less confusing, but it's how I convinced myself that the compiler knows what it's doing here.

这篇关于Scala中的Existensic类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆