2011-10-26 14 views
8

मेरे पास एक नक्शा है जहां दोनों कुंजी और मान सामान्य प्रकार हैं। कुछ इस तरह:पैरामीटरयुक्त प्रकारों से संबंधित

Map[Foo[A], Bar[A]] 

क्या मैं व्यक्त करना चाहते हैं उस प्रकार A नक्शे में प्रत्येक कुंजी-मान पेयर के लिए अलग अलग हो सकता है, लेकिन हर कुंजी हमेशा मूल्य के रूप में एक ही प्रकार के साथ पैरामिट्रीकृत है कि यह नक्शा है। तो Foo[Int] हमेशा Bar[Int] पर नक्शा करता है, Foo[String] हमेशा Bar[String] पर नक्शा करता है, और आगे भी।

क्या कोई इसे व्यक्त करने का तरीका जानता है?

संपादित करें:

यहाँ बात की तरह मैं ऐसा करने की कोशिश कर रहा हूँ एक उदाहरण है:

trait Parameter // not important what it actually does 

class Example { 
    val handlers: Map[_ <: Parameter, (_ <: Parameter) => _] = Map() 

    def doSomething() { 
    for ((value, handler) <- handlers) { 
     handler(value) 
    } 
    } 
} 

विचार यह है कि एक मूल्य हमेशा एक समारोह है कि इसे स्वीकार कर सकते करने के लिए नक्शे होगा एक पैरामीटर के रूप में, लेकिन जैसा कि कोड अब लिखा गया है, संकलक इसे नहीं जान सकता है।

+0

वह पंक्ति स्वयं संकलित नहीं होती है, स्कैला को उन प्रकारों को कहीं से चुनने की आवश्यकता होती है (या तो कक्षा या विधि प्रकार एनोटेशन, या एक अमूर्त प्रकार) क्या आप हमें दिखा सकते हैं कोड? –

+0

यह http://stackoverflow.com/questions/7401329/map-from-classtto-t-without-casting – michid

उत्तर

2

, यह स्काला में एक विषम नक्शा परिभाषित करना संभव है। यहाँ एक स्केच है:

class HMap[A[_], B[_]] extends Iterable[HMap.Mapping[A, B, _]] { 
    private val self = mutable.Map[A[_], B[_]]() 

    def toMapping[T](a: A[_], b: B[_]): HMap.Mapping[A, B, T] = { 
    HMap.Mapping(a.asInstanceOf[A[T]], b.asInstanceOf[B[T]]) 
    } 

    def iterator: Iterator[HMap.Mapping[A, B, _]] = 
    new Iterator[HMap.Mapping[A, B, _]] { 
     val sub = self.iterator 

     def hasNext = sub.hasNext 
     def next(): HMap.Mapping[A, B, _] = { 
     val (key, value) = sub.next() 
     toMapping(key, value) 
     } 
    } 

    def update[T](key: A[T], value: B[T]) = (self(key) = value) 
    def get[T](key: A[T]) = self.get(key).asInstanceOf[Option[B[T]]] 
    def apply[T](key: A[T]) = self(key).asInstanceOf[B[T]] 
} 

object HMap { 
    case class Mapping[A[_], B[_], T](val key: A[T], val value: B[T]) 
} 

यह आंतरिक रूप से एक नक्शा के बजाय मैपिंग का एक लिंक की गई सूची का उपयोग करके पूरी तरह से typesafe बनाया जा सकता है, लेकिन इस प्रदर्शन के लिए बेहतर है।

मेरी मूल उदाहरण इस प्रकार दिखाई देगा:

object Example { 
    type Identity[T] = T 
    type Handler[T] = (T) => _ 

    val handlers = new HMap[Identity, Handler] 

    def doSomething() { 
    for (HMap.Mapping(value, handler) <- handlers) { 
     handler(value) 
    } 
    } 
} 

यह लगभग एकदम सही है, को छोड़कर मैं सीमा को जोड़ने का तरीका यकीन नहीं है।

1

आप higher-rank polymorphic, विषम मानचित्र का वर्णन करने की कोशिश कर रहे हैं, जहां मानचित्र में प्रत्येक कुंजी-मूल्य जोड़ी का एक अलग प्रकार पैरामीटर हो सकता है। जितना ठंडा होगा, स्कैला की प्रकार प्रणाली आपको इस स्थिर रूप से व्यक्त करने की अनुमति नहीं देती है। मुझे लगता है कि सबसे अच्छा आप कर सकते हैं कुछ भयानक, असुरक्षित सहायक पद्धतियां निर्धारित करने के लिए है:

def get [A] (map: Map[Foo[_], Bar[_]], k: Foo[A]) : Bar[A] 
def put [A] (map: Map[Foo[_], Bar[_]], k: Foo[A], v: Bar[A]) 

आप इसे कुछ और अधिक सुरक्षित Manifest s का उपयोग करके रनटाइम पर प्रत्येक कुंजी-मान पेयर के प्रकार के मापदंडों वस्तु के बारे में जैसे सोचना करने के लिए बनाने के लिए सक्षम हो सकता है है, लेकिन मुझे यकीन है कि कैसे यह पता चला है के रूप में नहीं कर रहा हूँ ...

+0

पर एक करीबी डुप्लिकेट है, उन्हें असुरक्षित मानचित्र को encapsulating किसी ऑब्जेक्ट में तर्कसंगत तरीके से होना चाहिए - तो उपयोगकर्ता को एक प्राप्त होगा सुरक्षित इंटरफेस (या यहां तक ​​कि एक सुरक्षित, अगर प्रविष्टियों को केवल इस इंटरफेस के माध्यम से डाला जा सकता है, लेकिन यह अक्सर बहुत ही सीमित है)। आधार इंटरफ़ेस के लिए कोई प्रकट करने की आवश्यकता नहीं है। कार्यान्वयन के लिए पाठ्यक्रमों का उपयोग करने की आवश्यकता है, लेकिन आप यह सुनिश्चित कर सकते हैं कि वे असफल नहीं होंगे। – Blaisorblade

-2
scala> trait MyPair { 
    | type T 
    | val key:Foo[T] 
    | val value:Bar[T] 
    | } 
defined trait MyPair 

scala> var l:List[MyPair] = _ 
l: List[MyPair] = null 

scala> l = List(new MyPair{type T = Int; val key = new Foo[Int]{}; val value = new Bar[Int]{} }) 
l: List[MyPair] = List([email protected]) 

scala> l = List(new MyPair{type T = Int; val key = new Foo[Int]{}; val value = new Bar[Int]{} }, new MyPair {type T = String; val key = new Foo[String]{}; val value = new Bar[String]{} }) 
l: List[MyPair] = List([email protected], [email protected]) 

scala> l = List(new MyPair{type T = Int; val key = new Foo[Int]{}; val value = new Bar[Int]{} }, new MyPair {type T = String; val key = new Foo[String]{}; val value = new Bar[Int]{} }) 
<console>:11: error: overriding value value in trait MyPair of type Bar[this.T]; 
value value has incompatible type 
     l = List(new MyPair{type T = Int; val key = new Foo[Int]{}; val value = new Bar[Int]{} }, new MyPair {type T = String; val key = new Foo[String]{}; val value = new Bar[Int]{} }) 
0

मैंने एक मानचित्र लागू किया है जो आप चाहते हैं।आप यहाँ उस पर कुछ बुनियादी प्रलेखन पा सकते हैं: https://github.com/sullivan-/emblem/wiki/TypeBoundMaps

TypeBoundMaps एक ही प्रकार के पैरामीटर के साथ प्रकारों पर ध्यान देंगे, तो आप नक्शे में अपने कुंजी और मान प्रकार के लिए नए प्रकार के एक जोड़े को पेश करने की आवश्यकता होगी:

trait Parameter 
type Identity[P <: Parameter] = P 
type Handler[P <: Parameter] = (P) => _ 

अब आप नक्शे तुम इतनी तरह चाहते हैं बना सकते हैं:

trait P1 extends Parameter 
trait P2 extends Parameter 

val p1: P1 = new P1 {} 
val f1: Handler[P1] = { p1: P1 =>() } 

handlers += p1 -> f1 // add a new pair to the map                
val f2: Handler[P1] = handlers(p1) // retrieve a value from the map 
:

var handlers = TypeBoundMap[Parameter, Identity, Handler]() 

यहाँ नक्शा उपयोग करने के उदाहरण के एक जोड़े है

अब, पाश के लिए अपने उदाहरण में नकल करने के लिए, हम एक नए प्रकार TypeBoundPair है, जो एक कुंजी-मान पेयर है में लाने की जरूरत है जहां पैरामीटर मान मैच:

def handle[P <: Parameter](pair: TypeBoundPair[Parameter, Identity, Handler, P]): Unit = { 
    pair._2(pair._1) 
} 

handlers.foreach { pair => handle(pair) } 

Identity शुरू करने के पीछे विचार और Handler प्रकारों को यहां अधिक विस्तार से समझाया गया है: http://tinyurl.com/multi-tparam

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