Sự khác nhau giữa suy luận kiểu của các tham số kiểu phương thức và lớp trong khớp mẫu


9

Tại sao khớp mẫu lại hoạt động khác nhau khi tham số kiểu xuất phát từ một phương thức kèm theo trái ngược với một lớp kèm theo? Ví dụ,

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

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

đưa ra lỗi

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

Trong khi nó biên dịch thành công khi Atham số kiểu phương thức

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

Câu hỏi dựa trên phân tích của Daniel , mà tôi đã từng cố gắng đưa ra câu trả lời cho câu hỏi tương tự.

Câu trả lời:


4

Tôi không có câu trả lời hoàn chỉnh 100%, nhưng tôi có một con trỏ có thể đủ cho bạn.

Trình biên dịch Scala xử lý các GADT (Các kiểu dữ liệu đại số tổng quát) theo một cách rất riêng. Một số trường hợp được giải quyết với xử lý đặc biệt, một số trường hợp không được giải quyết. Dotty đang cố gắng lấp đầy hầu hết các lỗ hổng và nó đã giải quyết được rất nhiều vấn đề liên quan, tuy nhiên vẫn còn khá nhiều vấn đề mở .

Ví dụ điển hình về xử lý GADT đặc biệt trong trình biên dịch Scala 2 rất liên quan đến trường hợp sử dụng của bạn. Nếu chúng ta hãy xem:

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

và chúng tôi tuyên bố rõ ràng kiểu trả về là A:

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

nó sẽ biên dịch tốt IDE của bạn có thể phàn nàn, nhưng trình biên dịch sẽ cho phép nó đi qua. Phương thức nói rằng nó trả về một A, nhưng trường hợp khớp mẫu đánh giá thành một Int, theo lý thuyết không nên biên dịch. Tuy nhiên, việc xử lý đặc biệt các GADT trong trình biên dịch cho biết điều đó tốt, bởi vì trong nhánh khớp mẫu cụ thể đó Ađã được "cố định" thành một Int(vì chúng tôi khớp với Derivedđó là một Base[Int]).

Tham số loại chung cho GADT (trong trường hợp của chúng tôi A) phải được khai báo ở đâu đó. Và đây là phần thú vị - xử lý trình biên dịch đặc biệt chỉ hoạt động khi được khai báo là tham số loại của phương thức kèm theo . Nếu nó đến từ một thành viên loại hoặc một tham số loại của đặc điểm / lớp kèm theo, thì nó không được biên dịch, như bạn đã chứng kiến.

Đây là lý do tại sao tôi nói đó không phải là câu trả lời hoàn chỉnh 100% - tôi không thể chỉ ra một địa điểm cụ thể (chẳng hạn như thông số chính thức) có tài liệu này đúng. Nguồn xử lý của GADTs trong Scala đi xuống đến một vài của blogposts , mà là tuyệt vời bằng cách này, nhưng nếu bạn muốn nhiều hơn thế bạn sẽ phải thâm nhập vào mã trình biên dịch cho mình. Tôi đã thử thực hiện chính xác điều đó và tôi nghĩ rằng nó đi vào phương pháp này , nhưng nếu bạn thực sự muốn đi sâu hơn, bạn có thể muốn ping ai đó có kinh nghiệm hơn với cơ sở mã trình biên dịch Scala.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.