voglio usare istanze di oggetti come moduli/funtori, più o meno come illustrato di seguito:Come utilizzare gli oggetti come moduli/funtori in 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 {...}
}
In modo che posso creare un'istanza diversa calcolo per ogni reticolo (le operazioni che si esibiranno bisogno delle informazioni di cui sono i valori massimi e minimi del reticolo). Voglio essere in grado di mescolare espressioni dello stesso calcolo, ma non mi è permesso mescolare espressioni di tipi diversi. Fin qui tutto bene. Posso creare le mie istanze di calcolo, ma il problema è che non posso scrivere funzioni in altre classi che le manipolano.
Ad esempio, sto cercando di creare un parser per leggere le espressioni da un file e restituirle; Stavo anche cercando di scrivere un generatore di espressioni casuali da utilizzare nei miei test con ScalaCheck. Risulta che ogni volta che una funzione genera un oggetto Expr non posso usarlo al di fuori della funzione. Anche se creo l'istanza di Calcolo e la passiamo come argomento alla funzione che a sua volta genererà gli oggetti Expr, il ritorno della funzione non viene riconosciuto come dello stesso tipo degli oggetti creati al di fuori della funzione.
Forse il mio inglese non è abbastanza chiaro, permettetemi di provare un esempio di quello che vorrei fare (non il vero generatore di ScalaCheck, ma abbastanza vicino).
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))
}
}
}
Ora, se provo a compilare il codice di cui sopra ricevo un sacco di
error: type mismatch; found : plg.mvfml.Calculus[E]#Expr required: c.Expr case 0 => new c.Neg(genRndExpr(c, level+1))
E lo stesso accade se provo a fare qualcosa di simile:
val boolCalc = new Calculus(Bool)
val e1: boolCalc.Expr = genRndExpr(boolCalc)
prega di notare che il generatore stesso non è preoccupante, ma dovrò fare cose simili (ad es. creare e manipolare espressioni di istanze di calcolo) molto sul resto del sistema.
Sto facendo qualcosa di sbagliato? È possibile fare ciò che voglio fare?
L'assistenza su questo argomento è altamente necessaria e apprezzata. Grazie mille in anticipo.
Dopo aver ricevuto risposta da Apocalisp e averlo provato.
Grazie mille per la risposta, ma ci sono ancora alcuni problemi. La soluzione proposta era quello di cambiare la firma della funzione da:
def genRndExpr[E, C <: Calculus[E]](c: C, level: Int): C#Expr
Ho cambiato la firma per tutte le funzioni coinvolte: getRndExpr, getRndVal e getRndVar.E ho ottenuto lo stesso messaggio di errore in tutto il mondo che io chiamo queste funzioni e ottenuto il seguente messaggio di errore:
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)
Dal momento che il compilatore sembrava essere in grado di capire i tipi giusti ho cambiato tutti i chiamata di funzione per essere come di seguito:
case 0 => new c.Neg(genRndExpr[E,C](c, level+1))
Dopo questo, sui primi 2 chiamate di funzione (genRndVal e genRndVar) non ci sono stati errori di compilazione, ma sui seguenti 3 chiamate (chiamate ricorsive a genRndExpr), dove il ritorno della funzione viene utilizzata per costruire un nuovo oggetto Expr Ho ricevuto il seguente errore:
error: type mismatch; found : C#Expr required: c.Expr case 0 => new c.Neg(genRndExpr[E,C](c, level+1))
Quindi, di nuovo, sono bloccato. Qualsiasi aiuto sarà apprezzato.
Il titolo della domanda è un po 'fuorviante. Prendi in considerazione qualcosa come "Come fare riferimento alle classi interne da expternal relativamente allo scope di classe?" – Alexey