Ich möchte eine Klasse C
zum Speichern von Werten verschiedener numerischer Typen sowie Boolean implementieren. Darüber hinaus möchte ich in der Lage sein, Instanzen dieser Klasse zu betreiben, zwischen den Typen zu konvertieren Int --> Double
und Boolean -> Int
, dh Boolean + Boolean
, Int + Boolean
, Boolean + Int
, Double + Double
usw. zu addieren und das kleinstmögliche zurückzugeben Geben Sie (Int
oder Double
) wann immer möglich ein.Wie wird eine implizite Konvertierung eingerichtet, um Arithmetik zwischen numerischen Typen zu ermöglichen?
Bisher kam ich mit auf dem Punkt:
abstract class SemiGroup[A] { def add(x:A, y:A):A }
class C[A] (val n:A) (implicit val s:SemiGroup[A]) {
def +[T <% A](that:C[T]) = s.add(this.n, that.n)
}
object Test extends Application {
implicit object IntSemiGroup extends SemiGroup[Int] {
def add(x: Int, y: Int):Int = x + y
}
implicit object DoubleSemiGroup extends SemiGroup[Double] {
def add(x: Double, y: Double):Double = x + y
}
implicit object BooleanSemiGroup extends SemiGroup[Boolean] {
def add(x: Boolean, y: Boolean):Boolean = true;
}
implicit def bool2int(b:Boolean):Int = if(b) 1 else 0
val n = new C[Int](10)
val d = new C[Double](10.5)
val b = new C[Boolean](true)
println(d + n) // [1]
println(n + n) // [2]
println(n + b) // [3]
// println(n + d) [4] XXX - no implicit conversion of Double to Int exists
// println(b + n) [5] XXX - no implicit conversion of Int to Boolean exists
}
Dies ist für manche Fälle funktioniert (1, 2, 3), aber nicht für (4, 5). Der Grund ist, dass es eine implizite Erweiterung des Typs von niedriger auf höher gibt, aber nicht umgekehrt. In gewisser Weise das Verfahren
def +[T <% A](that:C[T]) = s.add(this.n, that.n)
irgendwie einen Partner Methode haben muss, die etwas aussehen würde:
def +[T, A <% T](that:C[T]):T = that.s.add(this.n, that.n)
aber das aus zwei Gründen nicht kompilieren, erstens, dass der Compiler nicht this.n
umwandeln kann Geben Sie T
ein (auch wenn wir die Sichtgrenze angeben A <% T
), und zweitens, selbst wenn es in der Lage wäre, this.n
zu konvertieren, werden die beiden Methoden +
mehrdeutig.
Sorry, das ist so lang. Jede Hilfe würde sehr geschätzt werden! Ansonsten scheint es, dass ich alle Operationen explizit zwischen allen Typen schreiben muss. Und es würde haarig werden, wenn ich zusätzliche Typen hinzufügen müsste (Complex
steht als nächstes auf der Speisekarte ...).
Vielleicht hat jemand einen anderen Weg, um das alles zusammen zu erreichen? Fühlt sich an, als gäbe es etwas Einfaches, das ich übersehe.
Vielen Dank im Voraus!
Ahha! Ich sehe, wie das funktioniert - danke! Das Hinzufügen eines 'Boolean' stellte sich in der Tat als einfach heraus und die LUB von' Numeric' wird nicht zu schwierig für 'Complex' zu ändern sein. Ich bin neugierig - Sie scheinen diese Lösung im Ärmel zu haben, in welchem Kontext sind Sie auf dieses Problem gestoßen? Auch ich habe versucht, die Leistung dieser Lösung zu testen und summiert eine Million 'C [Int]' s scheint etwa fünf Mal langsamer als eine Million 'Int's ... Irgendwelche Gedanken darüber, wie ich anfangen soll das optimieren? – ostolop
Ich habe das während einer Diskussion mit @extempore im IRC herumgespielt, es löste kein bestimmtes Problem von mir. 5x Overhead klingt angesichts der Indirektion nicht so schlecht. Sie könnten 'wc.a2b' und' wc.a2c' direkt aufrufen, anstatt die Methode 'unify' zu verwenden. Momentan sind die Ein- und Ausgaben von 'NumeriC# plus' geboxt, hoffentlich wird eine zukünftige Version von Scala einen Weg finden, dieses Problem zu lösen. – retronym
@retronym Eigentlich ... initiierte ich diese Diskussion. :-) –