简体   繁体   English

Scala结构类型和存在类型问题

[英]Scala Structural type and existential type issue

My question is that in the following snippet, c2 can pass compilation but t2 fail. 我的问题是,在下面的代码片段中,c2可以通过编译,但t2失败。 why? 为什么?

  type PairT[A, B] = { //structural type
    type T1 = A
    type T2 = B
  }
  class PairC[A, B] {
    type T1 = A
    type T2 = B
  }
case class TMap[A, B](a: A, b: B)
type MapC2[A] = TMap[p.T1, p.T2] forSome { val p: PairC[A, A] }
type MapT2[A] = TMap[p.T1, p.T2] forSome { val p: PairT[A, A] }
  val c2: MapC2[Int] = TMap(1,2)
  val t2: MapT2[Int] = TMap(1,2)

Recently I've had an interesting scala riddle that involves existential types and type aliases ( https://softwaremill.com/scala-riddle ) and I figured out that when type alias doesn't work we should try with bounded abstract type members. 最近我有一个有趣的scala谜语涉及存在类型和类型别名( https://softwaremill.com/scala-riddle ),我发现当类型别名不起作用时,我们应该尝试使用有界抽象类型成员。

I haven't figured out any pattern that could tell me which kind of type member I need to apply in particular situation. 我还没有弄清楚任何模式可以告诉我在特定情况下我需要应用哪种类型的成员。 I can't find answer in the documentation, maybe it's an implementation detail? 我在文档中找不到答案,也许这是一个实现细节?

I hope that there is someone who would help me find such pattern or at least give some new clues.. 我希望有人能帮助我找到这样的模式或至少给出一些新的线索..

How I made your code working 我如何使你的代码工作

Inside PairT I replaced type aliases ( type T1 = A ) with tightly bounded abstract types ( type T1 >: A <: A ) and .. it works (scalac 2.11.4). PairT内部,我用紧密有界的抽象类型( type T1 >: A <: A )替换了类型别名( type T1 = A ),并且它起作用(scalac 2.11.4)。

What's more interesting - PairC , which is a concrete class, will work only with type aliases - if I try to replace them with bounded abstract type members it raises a compilation error. 更有趣的是 - PairC ,它是一个具体类,只能使用类型别名 - 如果我尝试用有界抽象类型成员替换它们,则会引发编译错误。

Below is the whole code, after my modifications: 以下是我修改后的整个代码:

package so1

import scala.language.existentials

object SOPuzzle {

  type PairT[F, S] = {
    type T1 >: F <: F
    type T2 >: S <: S
  }

  class PairC[F, S] {
    type T1 = F
    type T2 = S
  }

  case class TMap[T, U](a: T, b: U) {
    def consumeA(a: T): T = a
    def consumeB(b: U): U = b
  }

  type MapC2[A] = TMap[p.T1, p.T2] forSome {val p: PairC[A, A]}

  type MapC2V2[A] = TMap[PairC[A, A]#T1, PairC[A,A]#T2]

  type MapT2[A] = TMap[p.T1, p.T2] forSome {val p: PairT[A, A]}

  type MapT2V2[A] = TMap[PairT[A, A]#T1, PairT[A, A]#T2]

  val c2: MapC2[Int] = TMap(1, 2)
  val c2v2: MapC2V2[Int] = TMap(1, 2)
  val t2: MapT2[Int] = TMap(1, 2)
  val t2v2: MapT2V2[Int] = TMap(1, 2)

  val i1:Int = c2.consumeA(0)
  val i2:Int = c2.consumeB(0)

  val i3:Int = c2v2.consumeA(0)
  val i4:Int = c2v2.consumeB(0)

  val i5:Int = t2.consumeA(0)
  val i6:Int = t2.consumeB(0)

  val i7:Int = t2v2.consumeA(0)
  val i8:Int = t2v2.consumeB(0)
}

I think it's an inference bug (or maybe a limitation) concerning the type construct. 我认为这是关于type构造的推理错误(或者可能是限制)。

Edit: the error message was the first thing that made me think it was a bug: 编辑:错误消息是让我觉得它是一个错误的第一件事:

"type mismatch; found : Int(1) required: A" “类型不匹配;发现:需要Int(1):A”

If you split the last line in to 2, ie 如果将最后一行拆分为2,即

val t3 = TMap(1,2)
val t2: MapT2[Int] = t3

, then it produces a similarly pongy message: ,然后它产生一个类似的pongy消息:

"type mismatch; found : Test1.this.TMap[Int,Int] required: Test1.this.MapT2[Int] (which expands to) Test1.this.TMap[A,A]" “类型不匹配;找到:Test1.this.TMap [Int,Int] required:Test1.this.MapT2 [Int](扩展为)Test1.this.TMap [A​​,A]”

Given that A is a 'symbol' and Int is a class, it seems like it's comparing apples and oranges. 鉴于A是'符号'而Int是一个类,它似乎是在比较苹果和橙子。 Sorry I can't take this logic any further! 对不起,我不能再采取这种逻辑了!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM