我想使用對象實例爲模塊/函子,更多或更少的,如下所示:如何在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 {...}
}
所以,我可以爲每個晶格創建不同的演算實例(我將執行的操作需要其的信息是格子的最大值和最小值)。我希望能夠混合相同演算的表達式,但不能混合不同表達式。到現在爲止還挺好。我可以創建我的微積分實例,但問題是我不能在其他操作它們的類中編寫函數。
例如,我想創建一個解析器從文件中讀取表達式並返回它們;我還試圖編寫一個隨機表達式生成器用於我的ScalaCheck測試。原來每次函數生成一個Expr對象時,我都不能在函數之外使用它。即使我創建了Calculus實例並將其作爲參數傳遞給函數,該函數又會生成Expr對象,但函數的返回結果不會被識別爲與函數外部創建的對象類型相同。
也許我的英語不夠清楚,讓我試試,我想做些什麼玩具的例子(不是真正的ScalaCheck發電機,但足夠接近)。現在
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))
}
}
}
,如果我嘗試編譯上面的代碼中,我得到很多的
error: type mismatch; found : plg.mvfml.Calculus[E]#Expr required: c.Expr case 0 => new c.Neg(genRndExpr(c, level+1))
而同樣的情況,如果我嘗試做這樣的事情:
val boolCalc = new Calculus(Bool)
val e1: boolCalc.Expr = genRndExpr(boolCalc)
請注意,生成器本身並不關心,但我需要在系統的其他部分做很多類似的事情(即創建和操作微積分實例表達式)。
我做錯了什麼? 是否有可能做我想做的事情?
在這個問題上的幫助是非常需要和讚賞。提前致謝。
從Apocalisp收到答案並嘗試它之後。
非常感謝您的回答,但仍然存在一些問題。所提出的解決方案是函數的簽名改爲:
def genRndExpr[E, C <: Calculus[E]](c: C, level: Int): C#Expr
我改變了簽名所涉及的所有功能:getRndExpr,getRndVal和getRndVar。而我得到了相同的錯誤消息,我到處都調用這些函數,並得到了以下錯誤消息:
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)
由於編譯器似乎無法找出正確的類型我改變了所有的函數調用是象下面這樣:
case 0 => new c.Neg(genRndExpr[E,C](c, level+1))
在此之後,在第一2次函數調用(genRndVal和genRndVar)沒有編譯錯誤,但在以下3次調用(遞歸調用genRndExpr),其中該函數的返回用於建立一新的Expr對象我得到以下錯誤:
error: type mismatch; found : C#Expr required: c.Expr case 0 => new c.Neg(genRndExpr[E,C](c, level+1))
所以,我再次卡住了。任何幫助將不勝感激。
您的問題標題有點誤導。考慮類似於「如何將內部類從外部相對於類範圍引用?」 – Alexey 2010-04-10 14:28:52