chcę użyć instancji obiektu jako moduły/funktory, pokazane mniej więcej jak poniżej:Jak używać obiektów jako modułów/funktorów w Scali?
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 {...}
}
Tak, że mogę stworzyć inną instancję nazębnego dla każdego kraty (operacje będę wykonywał potrzebują informacji, które są maksymalną i minimalną wartością sieci). Chcę móc wymieszać wyrażenia z tego samego rachunku, ale nie można mieszać wyrażeń różnych. Jak na razie dobrze. Mogę tworzyć instancje rachunku różniczkowego, ale problem polega na tym, że nie mogę pisać funkcji w innych klasach, które nimi manipulują.
Na przykład próbuję utworzyć analizator składni do odczytywania wyrażeń z pliku i zwracania ich; Próbowałem również napisać generator losowych wyrażeń do wykorzystania w moich testach z ScalaCheck. Okazuje się, że za każdym razem, gdy funkcja generuje obiekt Expr, nie mogę go użyć poza funkcją. Nawet jeśli utworzę instancję Calculus i przekażę ją jako argument do funkcji, która z kolei wygeneruje obiekty Expr, to powrót funkcji nie zostanie rozpoznany jako obiekt tego samego typu, który został utworzony poza funkcją.
Może mój angielski nie jest wystarczająco jasny, pozwól mi spróbować zabawnego przykładu tego, co chciałbym zrobić (nie rzeczywistego generatora ScalaCheck, ale wystarczająco blisko).
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))
}
}
}
Teraz, gdy próbuję skompilować powyższy kod otrzymuję wiele
error: type mismatch; found : plg.mvfml.Calculus[E]#Expr required: c.Expr case 0 => new c.Neg(genRndExpr(c, level+1))
I to samo się dzieje, gdy próbuję zrobić coś takiego:
val boolCalc = new Calculus(Bool)
val e1: boolCalc.Expr = genRndExpr(boolCalc)
Należy pamiętać, że sam generator nie jest niepokojący, ale będę musiał zrobić podobne rzeczy (np. tworzyć i manipulować wyrażeniami instancji obliczeniowej) wiele na pozostałej części systemu.
Czy robię coś nie tak? Czy można robić to, co chcę?
Pomoc w tej sprawie jest bardzo potrzebna i doceniana. Z góry dziękuję.
Po otrzymaniu odpowiedzi od Apocalisp i wypróbowaniu jej.
Wielkie dzięki za odpowiedź, ale nadal istnieją pewne problemy. Proponowane rozwiązanie było zmienić podpis funkcji do:
def genRndExpr[E, C <: Calculus[E]](c: C, level: Int): C#Expr
zmieniłem podpis do wszystkich funkcji zaangażowanych: getRndExpr, getRndVal i getRndVar.I mam ten sam komunikat o błędzie wszędzie Wzywam tych funkcji i uzyskałem następujący komunikat o błędzie:
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)
Ponieważ kompilator wydawało się być w stanie zorientować się odpowiednie typy zmieniłem wszystkie wywołania funkcji być jak poniżej:
case 0 => new c.Neg(genRndExpr[E,C](c, level+1))
Po tym, na pierwszych 2 wywołań funkcji (genRndVal i genRndVar) nie było kompilacji błąd, ale na 3 następujących połączeń (rekurencyjne Wezwania do genRndExpr), gdzie powrót funkcja ta jest wykorzystywana do budowania nowy obiekt Expr Mam następujący błąd:
error: type mismatch; found : C#Expr required: c.Expr case 0 => new c.Neg(genRndExpr[E,C](c, level+1))
Więc znowu utknąłem. Każda pomoc zostanie doceniona.
Twój tytuł pytania jest nieco mylący. Zastanów się, jak "Jak oddzielić klasę wewnętrzną od eksponalnego w stosunku do zakresu klasy?" – Alexey