2009-02-26 29 views
10

Tôi muốn biết các loại thành viên hoạt động như thế nào trong Scala và cách tôi nên liên kết các loại.Nhập thông số so với loại thành viên trong Scala

Một cách tiếp cận là làm cho thông số loại có liên quan. Ưu điểm của phương pháp này là tôi có thể quy định phương sai của loại và tôi có thể chắc chắn rằng một loại phụ không thay đổi loại. Những bất lợi là, mà tôi không thể suy ra các tham số kiểu từ loại trong một chức năng.

Cách tiếp cận thứ hai là làm cho loại liên kết là thành viên của loại thứ hai, có vấn đề mà tôi không thể quy định giới hạn trên các loại liên kết và do đó, tôi không thể sử dụng loại tham số chức năng (khi x: x, x # T có thể không phải trong bất kỳ mối quan hệ với XT)

một ví dụ cụ thể sẽ là:

tôi có một đặc điểm cho DFAs (có thể là không có tham số type)

trait DFA[S] { /* S is the type of the symbols in the alphabet */ 
    trait State { def next(x : S); } 
    /* final type Sigma = S */ 
} 

và tôi muốn tạo một hàm để chạy DFA này qua một chuỗi đầu vào, và tôi muốn

  • chức năng phải thực hiện bất cứ điều gì <% Seq[alphabet-type-of-the-dfa] as type chuỗi đầu vào
  • chức năng gọi không cần phải xác định các thông số chủng loại, tất cả phải được suy ra
  • Tôi muốn giống như hàm được gọi với kiểu DFA cụ thể (nhưng nếu có một giải pháp trong đó hàm sẽ không có tham số kiểu cho DFA thì OK)
  • các loại bảng chữ cái phải không bị giới hạn (ví dụ: phải có một DFA cho Char cũng như cho một lớp người dùng định nghĩa chưa được biết đến)
  • các DFAs với các loại bảng chữ cái khác nhau là không phân nhóm

Tôi cố gắng này:

def runDFA[S, D <: DFA[S], SQ <% Seq[S]](d : D)(seq : SQ) = .... 

tác phẩm này , ngoại trừ loại S không được phỏng đoán ở đây, vì vậy tôi phải viết toàn bộ danh sách tham số kiểu trên mỗi trang gọi.

def runDFA[D <: DFA[S] forSome { type S }, SQ <% Seq[D#Sigma]](... same as above 

này đã không làm việc (tham chiếu vòng tròn không hợp lệ để gõ D ??? (nó là gì?))

Tôi cũng xóa tham số kiểu, tạo ra một loại trừu tượng Sigma và cố gắng ràng buộc kiểu đó trong các lớp bê tông. runDFA sẽ trông như thế

def runDFA[D <: DFA, SQ <% Seq[D#Sigma]](... same as above 

nhưng điều này chắc chắn chạy vào các vấn đề như "loại không phù hợp: dự kiến ​​dfa.Sigma, có D#Sigma"

Bất kỳ ý tưởng? Con trỏ?

Edit:

Như câu trả lời cho thấy không có cách nào đơn giản để làm điều này, ai đó có thể giải thích thêm về lý do tại sao là nó không thể và những gì sẽ phải được thay đổi để nó làm việc?Lý do tôi muốn runDFA ro là một chức năng miễn phí (không phải là một phương pháp) là tôi muốn các chức năng tương tự khác, như giảm thiểu tự động, hoạt động ngôn ngữ thông thường, chuyển đổi NFA-to-DFA, hệ số ngôn ngữ, v.v ... và có tất cả điều này bên trong một lớp học là chỉ chống lại hầu như bất kỳ nguyên tắc thiết kế OO.

+0

Ồ, tôi nghĩ bạn muốn nói điều này: http://www.huygens-fokker.org/scala/ – MusiGenesis

Trả lời

3

Trước hết, bạn không cần parameterisation SQ <% Seq [ S]. Viết tham số phương thức là Seq [S]. Nếu SQ <% Seq [S] thì bất kỳ thể hiện của nó được chuyển đổi hoàn toàn thành Seq [S] (nghĩa là <% có nghĩa là), vì vậy khi được chuyển thành Seq [S] trình biên dịch sẽ tự động chèn chuyển đổi.

Ngoài ra, những gì Jorge đã nói về các thông số loại trên D và biến nó thành phương thức lưu giữ DFA. Do cách thức các lớp bên trong hoạt động trong Scala, tôi sẽ khuyên mạnh mẽ đặt runDFA trên DFA. Cho đến khi công cụ đánh máy phụ thuộc vào đường dẫn, việc xử lý các lớp bên trong của một số lớp bên ngoài có thể hơi đau.

Vì vậy, bây giờ bạn có

trait DFA[S]{ 
    ... 

    def runDFA(seq : Seq[S]) = ... 
} 

Và runDFA là tất cả của một đột ngột khá dễ dàng để suy ra các thông số kiểu cho: Nó không có bất kỳ.

3

Suy luận kiểu Scala đôi khi để lại nhiều điều mong muốn.

Có lý do nào khiến bạn không thể có phương pháp bên trong đặc điểm DFA của mình không?

def run[SQ <% Seq[S]](seq: SQ) 

Nếu bạn không cần D param sau đó, bạn cũng có thể thử xác định phương pháp của bạn mà không có nó:

def runDFA[S, SQ <% Seq[S]](d: DFA[S])(seq: SQ) = ... 
0

Một số thông tin hữu ích về cách hai khác:

Từ những hình thù guide:

Nếu không có tham số kiểu bạn không thể làm cho các loại phụ thuộc, ví dụ

trait Generic[A] { 
    type Repr 
    def to(value: A): Repr 
    def from(value: Repr): A 
} 

import shapeless.Generic 
def getRepr[A](value: A)(implicit gen: Generic[A]) = 
    gen.to(value) 

Đây kiểu trả về bởi to tùy thuộc vào loại đầu vào A (do ngầm định được cung cấp tùy thuộc vào A):

case class Vec(x: Int, y: Int) 
case class Rect(origin: Vec, size: Vec) 
getRepr(Vec(1, 2)) 
// res1: shapeless.::[Int,shapeless.::[Int,shapeless.HNil]] = 1 :: 2 :: 
    HNil 
getRepr(Rect(Vec(0, 0), Vec(5, 5))) 
// res2: shapeless.::[Vec,shapeless.::[Vec,shapeless.HNil]] = Vec(0,0) 
    :: Vec(5,5) :: HNil 

mà không thành viên kiểu này sẽ không thể:

trait Generic2[A, Repr] 
def getRepr2[A, R](value: A)(implicit generic: Generic2[A, R]): R = 
    ??? 

Chúng tôi sẽ phải vượt qua giá trị mong muốn của repr để getRepr như một tham số loại, effec vely làm getRepr vô dụng. Các intui ve cất đi từ điều này là các thông số kiểu là hữu ích như "đầu vào" và loại thành viên là hữu ích như "đầu ra".

vui lòng xem shapeless guide để biết chi tiết.

Các vấn đề liên quan