2010-04-09 28 views
6

Tôi muốn sử dụng trường hợp đối tượng là mô-đun/functors, nhiều hơn hoặc ít hơn như hình dưới đây:Làm thế nào để sử dụng các đối tượng như mô-đun/functors trong Scala?

abstract class Lattice[E] extends Set[E] { 
    val minimum: E 
    val maximum: E 
    def meet(x: E, y: E): E 
    def join(x: E, y: E): E 
    def neg(x: E): E 
} 

class Calculus[E](val lat: Lattice[E]) { 
    abstract class Expr 
    case class Var(name: String) extends Expr {...} 
    case class Val(value: E) extends Expr {...} 
    case class Neg(e1: Expr) extends Expr {...} 
    case class Cnj(e1: Expr, e2: Expr) extends Expr {...} 
    case class Dsj(e1: Expr, e2: Expr) extends Expr {...} 
} 

Vì vậy mà tôi có thể tạo ra một trường hợp tính toán khác nhau cho mỗi mạng (các hoạt động tôi sẽ thực hiện cần những thông tin trong đó là các giá trị tối đa và tối thiểu của mạng). Tôi muốn có thể kết hợp các biểu thức của cùng một phép tính nhưng không được phép trộn lẫn các biểu thức của các phép tính khác nhau. Càng xa càng tốt. Tôi có thể tạo ra các cá thể tính toán của mình, nhưng vấn đề là tôi không thể viết các hàm trong các lớp khác để thao tác chúng.

Ví dụ: Tôi đang cố gắng tạo trình phân tích cú pháp để đọc các biểu thức từ một tệp và trả lại chúng; Tôi cũng đang cố gắng viết một trình tạo biểu thức ngẫu nhiên để sử dụng trong các thử nghiệm của tôi với ScalaCheck. Hóa ra mỗi khi một hàm tạo ra một đối tượng Expr, tôi không thể sử dụng nó bên ngoài hàm. Thậm chí nếu tôi tạo ra thể hiện Calculus và chuyển nó thành một đối số cho hàm sẽ lần lượt tạo ra các đối tượng Expr, thì hàm trả về của hàm không được nhận dạng như là cùng kiểu của các đối tượng được tạo bên ngoài hàm.

Có lẽ tiếng anh của tôi không đủ rõ ràng, hãy để tôi thử một ví dụ về đồ chơi về những gì tôi muốn làm (không phải máy phát ScalaCheck thực, nhưng đủ gần).

def genRndExpr[E](c: Calculus[E], level: Int): Calculus[E]#Expr = { 
    if (level > MAX_LEVEL) { 
    val select = util.Random.nextInt(2) 
    select match { 
     case 0 => genRndVar(c) 
     case 1 => genRndVal(c) 
    } 
    } 
    else { 
    val select = util.Random.nextInt(3) 
    select match { 
     case 0 => new c.Neg(genRndExpr(c, level+1)) 
     case 1 => new c.Dsj(genRndExpr(c, level+1), genRndExpr(c, level+1)) 
     case 2 => new c.Cnj(genRndExpr(c, level+1), genRndExpr(c, level+1)) 
    } 
    } 
} 

Bây giờ, nếu tôi cố gắng biên dịch mã trên tôi nhận được rất nhiều

 
error: type mismatch; 
found : plg.mvfml.Calculus[E]#Expr 
required: c.Expr 
     case 0 => new c.Neg(genRndExpr(c, level+1)) 

Và tương tự xảy ra nếu tôi cố gắng làm điều gì đó như:

val boolCalc = new Calculus(Bool) 
val e1: boolCalc.Expr = genRndExpr(boolCalc) 

Xin lưu ý rằng chính máy phát điện không phải là mối quan tâm, nhưng tôi sẽ cần phải làm những việc tương tự (tức là tạo và thao tác các biểu thức thể hiện tính toán) rất nhiều trên phần còn lại của hệ thống.

Tôi có làm gì sai không? Tôi có thể làm những gì tôi muốn làm không?

Trợ giúp về vấn đề này là rất cần thiết và được đánh giá cao. Cảm ơn rất nhiều trước.


Sau khi nhận được câu trả lời từ Apocalisp và dùng thử.

Cảm ơn rất nhiều câu trả lời nhưng vẫn còn một số vấn đề. Giải pháp được đề xuất là thay đổi chữ ký của hàm thành:

def genRndExpr[E, C <: Calculus[E]](c: C, level: Int): C#Expr 

Tôi đã thay đổi chữ ký cho tất cả các chức năng liên quan: getRndExpr, getRndVal và getRndVar.Và tôi đã nhận được thông báo lỗi tương tự ở khắp mọi nơi tôi gọi các chức năng này và nhận được thông báo lỗi sau:

 
error: inferred type arguments [Nothing,C] do not conform to method genRndVar's 
type parameter bounds [E,C <: plg.mvfml.Calculus[E]] 
     case 0 => genRndVar(c) 

Kể từ khi trình biên dịch dường như không thể tìm ra đúng loại tôi đã thay đổi tất cả các cuộc gọi chức năng để được như dưới đây:

case 0 => new c.Neg(genRndExpr[E,C](c, level+1)) 

sau này, trên 2 chức năng cuộc gọi đầu tiên (genRndVal và genRndVar) không có lỗi biên dịch, nhưng trên 3 cuộc gọi sau đây (cuộc gọi đệ quy để genRndExpr), nơi mà sự trở lại của các chức năng được sử dụng để xây dựng một đối tượng Expr mới tôi nhận được lỗi sau:

 
error: type mismatch; 
found : C#Expr 
required: c.Expr 
     case 0 => new c.Neg(genRndExpr[E,C](c, level+1)) 

Vì vậy, một lần nữa, tôi bị kẹt. Bất kỳ trợ giúp sẽ được đánh giá cao.

+0

Tiêu đề câu hỏi của bạn hơi gây hiểu nhầm. Hãy xem xét một cái gì đó như "Làm thế nào để giới thiệu các lớp bên trong từ bên ngoài tương đối với phạm vi lớp học?" – Alexey

Trả lời

3

Vấn đề là Scala không thể hợp nhất hai loại Calculus[E]#ExprCalculus[E]#Expr.

Những giao diện này giống với bạn, đúng không? Vâng, hãy xem xét rằng bạn có thể có hai phép tính riêng biệt trên một số loại E, mỗi loại có loại Expr riêng của chúng. Và bạn sẽ không muốn kết hợp các biểu thức của cả hai.

Bạn cần phải hạn chế các loại theo cách sao cho kiểu trả về giống kiểu Expr làm kiểu đối số Expr bên trong đối số Calculus của bạn. Những gì bạn phải làm điều này là:

def genRndExpr[E, C <: Calculus[E]](c: C, level: Int): C#Expr 
+0

Xin chào! Cảm ơn rất nhiều cho câu trả lời, nhưng vẫn còn một số vấn đề. Tôi đã thử bạn giải pháp. Tôi đã thay đổi chữ ký cho tất cả các chức năng liên quan: getRndExpr, getRndVal và getRndVar. Và tôi nhận được thông báo lỗi tương tự ở khắp mọi nơi tôi gọi những chức năng này. Tôi không thể mô tả đầy đủ vấn đề ở đây do thiếu không gian, vì vậy tôi sẽ chỉnh sửa nội dung của câu hỏi để có thể trả lời đúng. – Jeff

1

Nếu bạn không muốn lấy được một tính toán cụ thể từ các Calculus sau đó chỉ cần di chuyển expr phạm vi toàn cầu hoặc tham khảo thông qua phạm vi toàn cầu:

class Calculus[E] { 
    abstract class Expression 
    final type Expr = Calculus[E]#Expression 

    ... the rest like in your code 
} 

this question đề cập đến chính xác cùng một vấn đề.

Nếu bạn muốn thực hiện một subtype của Calculus và xác định lại expr có (những gì là khó xảy ra), bạn phải:

đặt getRndExpr vào lớp Calculus hoặc đặt getRndExpr thành một đặc điểm xuất phát:

trait CalculusExtensions[E] extends Calculus[E] { 
    def getRndExpr(level: Int) = ... 
    ... 
} 

tham khảo this luồng vì lý do tại sao.

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