2010-06-21 8 views
9

मैं विभिन्न संख्यात्मक प्रकारों के साथ-साथ बूलियन के मूल्यों को संग्रहीत करने के लिए कक्षा C को लागू करना चाहता हूं। इसके अलावा, मैं प्रकार के बीच, इस वर्ग के उदाहरण पर संचालित करने के लिए, परिवर्तित करने में सक्षम होना चाहते हैं जहां आवश्यक Int --> Double और Boolean -> Int, यानी,, छोटी संभव लौटने Boolean + Boolean, Int + Boolean, Boolean + Int, Int + Double, Double + Double आदि जोड़ने के लिए सक्षम होने के लिए टाइप करें (Int या Double) जब भी संभव हो।संख्यात्मक प्रकारों के बीच अंकगणित की अनुमति देने के लिए निहित रूपांतरण कैसे सेट करें?

अब तक मैं इस के साथ आया था:

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 
} 

यह कुछ मामलों के लिए काम करता है (1, 2, 3) लेकिन ऐसा नहीं करता के लिए (4, 5)। इसका कारण यह है कि नीचे से उच्च तक के प्रकार की अंतर्निहित चौड़ाई है, लेकिन दूसरी तरफ नहीं।

def +[T, A <% T](that:C[T]):T = that.s.add(this.n, that.n) 

लेकिन यह है कि दो कारणों के लिए संकलन नहीं करता है, सबसे पहले कि संकलक को this.n परिवर्तित नहीं कर सकते: एक तरह से, विधि

def +[T <% A](that:C[T]) = s.add(this.n, that.n) 

किसी भी तरह एक साथी विधि है कि कुछ ऐसा दिखाई देगा की जरूरत में T टाइप करें (भले ही हम व्यू बाउंड A <% T निर्दिष्ट करते हैं), और दूसरी बात यह है कि अगर this.n को कनवर्ट करने में सक्षम थे, तोविधियों को अस्पष्ट करने के बाद टाइप करें।

क्षमा करें यह बहुत लंबा है। कोई भी सहायताकाफी प्रशंसनीय होगी! अन्यथा ऐसा लगता है कि मुझे सभी प्रकार के बीच सभी परिचालनों को स्पष्ट रूप से लिखना है। और अगर मुझे अतिरिक्त प्रकार जोड़ना पड़ता है तो यह बालों वाली हो जाएगी (Complex मेनू पर अगला है ...)।

शायद किसी को यह सब हासिल करने का एक और तरीका है? ऐसा लगता है कि कुछ सरल है जो मैं देख रहा हूं।

अग्रिम धन्यवाद!

उत्तर

6

ठीक है, तो डैनियल!

मैंने बूलेन को अनदेखा करने के लिए समाधान को प्रतिबंधित कर दिया है, और केवल AnyVals के साथ काम करता है जिसमें कमजोर कम ऊपरी बाउंड है जिसमें Numeric का उदाहरण है। ये प्रतिबंध मनमाने ढंग से हैं, आप उन्हें हटा सकते हैं और प्रकारों के बीच अपने कमजोर अनुरूपता संबंध को एन्कोड कर सकते हैं - a2b और a2c के कार्यान्वयन कुछ रूपांतरण कर सकते हैं।

इसके दिलचस्प विचार करने के लिए कैसे निहित मापदंडों विरासत (प्रकार के अंतर्निहित पैरामीटर प्रदान करने के (व्युत्पन्न => बेस) या कमजोर अनुरूपता अनुकरण कर सकते हैं। वे वास्तव में शक्तिशाली हैं, खासकर जब प्रकार inferencer तुम बाहर में मदद करता है।

पहले, हमें A और B के सभी जोड़े के कमजोर लीस्ट ऊपरी बाउंड का प्रतिनिधित्व करने के लिए एक प्रकार की कक्षा की आवश्यकता है, जिसमें हम रुचि रखते हैं।

sealed trait WeakConformance[A <: AnyVal, B <: AnyVal, C] { 
    implicit def aToC(a: A): C 

    implicit def bToC(b: B): C 
} 

object WeakConformance { 
    implicit def SameSame[T <: AnyVal]: WeakConformance[T, T, T] = new WeakConformance[T, T, T] { 
    implicit def aToC(a: T): T = a 

    implicit def bToC(b: T): T = b 
    } 

    implicit def IntDouble: WeakConformance[Int, Double, Double] = new WeakConformance[Int, Double, Double] { 
    implicit def aToC(a: Int) = a 

    implicit def bToC(b: Double) = b 
    } 

    implicit def DoubleInt: WeakConformance[Double, Int, Double] = new WeakConformance[Double, Int, Double] { 
    implicit def aToC(a: Double) = a 

    implicit def bToC(b: Int) = b 
    } 

    // More instances go here! 


    def unify[A <: AnyVal, B <: AnyVal, C](a: A, b: B)(implicit ev: WeakConformance[A, B, C]): (C, C) = { 
    import ev._ 
    (a: C, b: C) 
    } 
} 

विधि unify रिटर्न टाइप C, जो प्रकार निहित मूल्यों की उपलब्धता के आधार पर अंतर्निहित तर्क ev के रूप में प्रदान करने के लिए inferencer से पता लगा है।

हम इसे आपके रैपर क्लास सी में निम्नानुसार प्लग कर सकते हैं, इसके लिए Numeric[WeakLub] भी आवश्यक है ताकि हम मान जोड़ सकें।

case class C[A <: AnyVal](val value:A) { 
    import WeakConformance.unify 
    def +[B <: AnyVal, WeakLub <: AnyVal](that:C[B])(implicit wc: WeakConformance[A, B, WeakLub], num: Numeric[WeakLub]): C[WeakLub] = { 
    val w = unify(value, that.value) match { case (x, y) => num.plus(x, y)}; 
    new C[WeakLub](w) 
    } 
} 

और अंत में, यह सब एक साथ डाल:

object Test extends Application { 
    val n = new C[Int](10) 
    val d = new C[Double](10.5) 

    // The type ascriptions aren't necessary, they are just here to 
    // prove the static type is the Weak LUB of the two sides. 
    println(d + n: C[Double]) // C(20.5) 
    println(n + n: C[Int]) // C(20) 
    println(n + d: C[Double]) // C(20.5) 
} 

Test 
+0

ahha! मैं देखता हूं कि यह कैसे काम करता है - धन्यवाद! 'बूलियन 'जोड़ना आसान हो गया, वास्तव में, और' संख्यात्मक 'के एलयूबी को' परिसर 'के लिए बदलना बहुत मुश्किल नहीं होगा। मैं उत्सुक हूं - ऐसा लगता है कि आपने यह समाधान अपनी आस्तीन को संभाला है, इस समस्या में आप किस संदर्भ में आए थे? इसके अलावा मैंने इस समाधान के प्रदर्शन की जांच करने की कोशिश की और दस लाख 'इंट]' का योग दस लाख से अधिक धीमा लगता है ... इंटेल के बारे में कोई विचार ... कैसे शुरू करना है इसे अनुकूलित करें? – ostolop

+0

आईआरसी पर @extempore के साथ चर्चा के दौरान मैंने इस के आसपास खेला, यह मेरी एक विशेष समस्या को हल नहीं कर रहा था। 5x ओवरहेड संकेत पर विचार करने में बहुत बुरा नहीं लगता है। आप 'unify' विधि का उपयोग करने के बजाय सीधे 'wc.a2b' और' wc.a2c' को कॉल कर सकते हैं। वर्तमान में 'न्यूमेरिक # प्लस' के इनपुट और आउटपुट को बॉक्स किया गया है, उम्मीद है कि स्कैला के भविष्य के संस्करण को उस समस्या को दूर करने का एक तरीका मिलेगा। – retronym

+0

@ वास्तविकता वास्तव में ... मैंने उस चर्चा की शुरुआत की। :-) –

3

ऐसा करने के लिए way है, लेकिन मैं इसे हल करने के लिए इसे retronym पर छोड़ दूंगा, क्योंकि उसने इस समाधान को लिखा था। :-)

संबंधित मुद्दे