ความแตกต่างระหว่างการอนุมานประเภทของเมธอดและพารามิเตอร์ประเภทคลาสในการจับคู่รูปแบบ


9

ทำไมการจับคู่รูปแบบทำงานแตกต่างกันเมื่อพารามิเตอร์ชนิดมาจากวิธีการปิดล้อมซึ่งตรงข้ามกับคลาสที่ล้อมรอบ ตัวอย่างเช่น,

trait Base[T]
case class Derived(v: Int) extends Base[Int]

class Test[A] {
  def method(arg: Base[A]) = {
    arg match {
      case Derived(_) => 42
    }
  }
}

ให้ข้อผิดพลาด

constructor cannot be instantiated to expected type;
 found   : A$A87.this.Derived
 required: A$A87.this.Base[A]
      case Derived(_) => 42
           ^

ในขณะที่มันประสบความสำเร็จในการรวบรวมเมื่อAเป็นพารามิเตอร์ประเภทวิธี

class Test {
  def method[A](arg: Base[A]) = {
    arg match {
      case Derived(_) => 42
    }
  }
}

คำถามนั้นมาจากการวิเคราะห์ของ Daniel ซึ่งฉันเคยพยายามให้คำตอบสำหรับคำถามที่คล้ายกัน

คำตอบ:


4

ฉันไม่มีคำตอบที่สมบูรณ์ 100% แต่ฉันมีตัวชี้ที่อาจเพียงพอสำหรับคุณ

คอมไพเลอร์ Scala เกี่ยวข้องกับ GADTs (ประเภทข้อมูลพีชคณิตทั่วไป) ในวิธีที่เฉพาะเจาะจงมาก บางกรณีแก้ไขได้ด้วยการจัดการพิเศษบางกรณีไม่ได้รับการแก้ไข บ้า ๆ บอ ๆ พยายามที่จะเติมเต็มที่สุดของหลุมและก็มีอยู่แล้วการแก้ไขปัญหามากที่เกี่ยวข้อง แต่ยังคงมีค่อนข้างน้อยเปิดคนได้เป็นอย่างดี

ตัวอย่างทั่วไปของการจัดการ GADT พิเศษในคอมไพเลอร์ Scala 2 นั้นเกี่ยวข้องกับกรณีการใช้งานของคุณมาก ถ้าเราดูที่:

def method[A](arg: Base[A]) = {
  arg match {
    case Derived(_) => 42
  }
}

และเราประกาศประเภทการส่งคืนอย่างชัดเจนว่าเป็นA:

def method[A](arg: Base[A]): A 

มันจะรวบรวมได้ดี IDE ของคุณอาจบ่น แต่คอมไพเลอร์จะปล่อยให้ผ่าน Method บอกว่ามันจะคืนค่าAแต่กรณีที่จับคู่รูปแบบจะประเมินเป็นอันIntซึ่งในทางทฤษฎีไม่ควรรวบรวม อย่างไรก็ตามการจัดการแบบพิเศษของ GADT ในคอมไพเลอร์กล่าวว่าใช้ได้เพราะในการจับคู่รูปแบบที่เฉพาะเจาะจงAนั้นได้รับการ "แก้ไข" ให้เป็นInt(เพราะเราจับคู่Derivedซึ่งเป็น a Base[Int])

พารามิเตอร์ประเภททั่วไปสำหรับ GADT (ในกรณีของเราA) จะต้องมีการประกาศที่ไหนสักแห่ง และนี่คือส่วนหนึ่งที่น่าสนใจ - การจัดการคอมไพเลอร์พิเศษใช้งานได้เฉพาะเมื่อมีการประกาศเป็นพารามิเตอร์ชนิดของวิธีการปิดล้อม ถ้ามันมาจากสมาชิกประเภทหรือพารามิเตอร์ประเภทของคุณลักษณะ / คลาสที่ล้อมรอบมันจะไม่คอมไพล์ตามที่คุณเห็นด้วยตัวคุณเอง

นี่คือเหตุผลที่ฉันบอกว่ามันไม่ใช่คำตอบที่สมบูรณ์ 100% - ฉันไม่สามารถชี้ไปยังสถานที่ที่เป็นรูปธรรม (เช่นข้อกำหนดอย่างเป็นทางการ) ซึ่งเอกสารนี้ถูกต้อง แหล่งที่มาของการจัดการ GADT ใน Scala นั้นมาลงที่บล็อกโพสต์สองสาม อัน ซึ่งยอดเยี่ยม แต่ถ้าคุณต้องการมากกว่านั้นคุณจะต้องขุดลงไปในคอมไพเลอร์โค้ดด้วยตัวเอง ฉันพยายามทำอย่างนั้นและฉันคิดว่าวิธีการนี้จะลงเอยแต่ถ้าคุณต้องการที่จะเจาะลึกลงไปจริงๆคุณอาจต้องการที่จะ ping คนที่มีประสบการณ์มากขึ้นด้วย codebase คอมไพเลอร์ Scala

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.