2013-01-06 12 views
9

मैं स्कैला संग्रह के लिए कुछ एक्सटेंशन विधियों को लिखने की कोशिश कर रहा हूं, और पूरी तरह से उन्हें उत्पन्न करने में परेशानी में भाग रहा हूं।मैं IsTraversableLike में सदस्य ए प्रकार का उपयोग कैसे करूं?

tailOption पर एक पहला प्रयास की तरह कुछ पैदावार:

implicit class TailOption[A, Repr <: GenTraversableLike[A, Repr]](val repr: Repr) { 
    def tailOption: Option[Repr] = 
    if (repr.isEmpty) None 
    else Some(repr.tail) 
} 

दुर्भाग्य से, यह काम नहीं करता:

scala> List(1,2,3).tailOption 
<console>:19: error: value tailOption is not a member of List[Int] 
       List(1,2,3).tailOption 

स्काला 2.10 IsTraversableLike प्रकार स्तरीय बात की इस तरह अनुकूलन में मदद करने के प्रदान करता है सभी संग्रहों के लिए (अजीब लोगों सहित, स्ट्रिंग्स की तरह)।

इसके साथ ही मैं उदाहरण के लिए tailOption काफी आसानी से लागू कर सकते हैं:

implicit class TailOption[Repr](val r: Repr)(implicit fr: IsTraversableLike[Repr]) { 
    def tailOption: Option[Repr] = { 
    val repr = fr.conversion(r) 
    if (repr.isEmpty) None 
    else Some(repr.tail) 
    } 
} 

scala> List(1,2,3).tailOption 
res12: Option[List[Int]] = Some(List(2, 3)) 

scala> "one".tailOption 
res13: Option[String] = Some(ne) 

परिणाम सही प्रकार की है: Option[<input-type>]। विशेष रूप से, मैं Repr प्रकार को संरक्षित करने में सक्षम हूं जो Repr लौटने वाली विधियों को कॉल करते हैं, जैसे 'पूंछ।

दुर्भाग्य से, मैं संग्रह के तत्वों के प्रकार को संरक्षित करने के लिए इस चाल का उपयोग नहीं कर सकता। मैं उन तरीकों को कॉल नहीं कर सकता जो एक तत्व लौटाते हैं।

IsTraversableLike में सदस्य ए है लेकिन यह बहुत उपयोगी प्रतीत नहीं होता है। विशेष रूप से मैं अपने मूल तत्व प्रकार का पुनर्निर्माण नहीं कर सकता हूं और सदस्य प्रकार के बराबर नहीं है। उदाहरण के लिए, आगे काम के बिना, headTailOption इस तरह दिखता है:

implicit class HeadTailOption[Repr](val r: Repr)(implicit val fr: IsTraversableLike[Repr]) { 
    def headTailOption: Option[(fr.A, Repr)] = { 
    val repr = fr.conversion(r) 
    if (repr.isEmpty) None 
    else Some(repr.head -> repr.tail) 
    } 
} 

scala> val Some((c, _)) = "one".headTailOption 
c: _1.fr.A forSome { val _1: HeadTailOption[String] } = o 

हम देख सकते हैं, ग एक अद्भुत बारोक प्रकार है। लेकिन, इस प्रकार है चार के बराबर नहीं:

scala> val fr = implicitly[IsTraversableLike[String]] 
fr: scala.collection.generic.IsTraversableLike[String] = [email protected] 

scala> implicitly[fr.A <:< Char] 
<console>:25: error: Cannot prove that fr.A <:< Char. 
       implicitly[fr.A <:< Char] 

मैं Repr[A] <: GenTraversableLike[A, Repr[A]] जिनमें से कोई भी मदद कर रहा सहित चाल के सभी प्रकार की कोशिश की है। किसी को भी बनाने के लिए मैजिक सॉस बाहर काम headTailOption के लिए सही प्रकार लौट सकते हैं:

val headTailString: Option[(Char, String)] = "one".headTailOption 
val headTailList: Option[(Int, List[Int])] = List(1,2,3).headTailOption 

उत्तर

3

एक आंशिक जवाब। आपने शायद IsTraversableLike के लिए स्कालाडोक उदाहरण से शुरू किया है। यह अभी भी एक निहित वर्ग के माध्यम से एक कदम में जाने के बजाय, निहित रूपांतरण को अलग करने और रैपर वर्ग को तत्काल करने के "पुराने दृष्टिकोण" का उपयोग करता है। ऐसा लगता है कि "पुराने दृष्टिकोण" करता है काम:

import collection.GenTraversableLike 
import collection.generic.IsTraversableLike 

final class HeadTailOptionImpl[A, Repr](repr: GenTraversableLike[A, Repr]) { 
    def headTailOption: Option[(A, Repr)] = { 
    if (repr.isEmpty) None 
    else Some(repr.head -> repr.tail) 
    } 
} 

implicit def headTailOption[Repr](r: Repr)(implicit fr: IsTraversableLike[Repr]): 
    HeadTailOptionImpl[fr.A,Repr] = new HeadTailOptionImpl(fr.conversion(r)) 

// `c` looks still weird: `scala.collection.generic.IsTraversableLike.stringRepr.A` 
val Some((c, _)) = "one".headTailOption 
val d: Char = c // ...but it really is a `Char`! 

val headTailString: Option[(Char, String)] = "one".headTailOption 
val headTailList: Option[(Int, List[Int])] = List(1,2,3).headTailOption 

मीलों बताते हैं के रूप में, विभाजन आवश्यक यह अंतर्निहित खोज और प्रकार निष्कर्ष के साथ काम करने के लिए लगता है।

एक अन्य समाधान है, हालांकि निश्चित रूप से कम सुंदर, तार और संग्रह के एकीकरण देने के लिए है:

trait HeadTailOptionLike[A, Repr] { 
    def headTailOption: Option[(A, Repr)] 
} 

implicit class GenHeadTailOption[A, Repr](repr: GenTraversableLike[A, Repr]) 
extends HeadTailOptionLike[A, Repr] { 
    def headTailOption = 
    if (repr.isEmpty) None 
    else Some(repr.head -> repr.tail) 
} 

implicit class StringHeadTailOption(repr: String) 
extends HeadTailOptionLike[Char, String] { 
    def headTailOption = 
    if (repr.isEmpty) None 
    else Some(repr.head -> repr.tail) // could use repr.charAt(0) -> repr.substring(1) 
} 

List(1,2,3).headTailOption 
"one".headTailOption 
+0

आपने मुझे इसे हराया। दुर्भाग्य से आश्रित विधि के बीच विभाजित विधि fr.A और प्रकार-पैरामीटरयुक्त वर्ग का उपयोग करना आवश्यक है, इसलिए मुझे विश्वास नहीं है कि एक अंतर्निहित वर्ग समाधान (वर्तमान में) संभव है। –

+0

हां, मैं अब एक ही निष्कर्ष पर आया था। निहित वर्ग निर्भर प्रकार के आवश्यक प्रकार परिवर्तन/अनुमान को पुन: पेश करने में सक्षम नहीं है ... –

0

आप इसे एक अंतर्निहित वर्ग के रूप में लिख सकते हैं अगर आप IsTraversableLike से प्रकार A निकालें।

import collection.generic.IsTraversableLike 

implicit class HeadTailOption[Repr,A0](val r: Repr)(implicit val fr: IsTraversableLike[Repr]{ type A = A0 }) { 
    def headTailOption: Option[(A0, Repr)] = { 
    val repr = fr.conversion(r) 
    if (repr.isEmpty) None 
    else Some(repr.head -> repr.tail) 
    } 
} 

या समतुल्य:

import collection.generic.IsTraversableLike 

type IsTraversableLikeAux[Repr,A0] = IsTraversableLike[Repr]{ type A = A0 } 

implicit class HeadTailOption[Repr,A](val r: Repr)(implicit val fr: IsTraversableLikeAux[Repr,A]) { 
    def headTailOption: Option[(A, Repr)] = { 
    val repr = fr.conversion(r) 
    if (repr.isEmpty) None 
    else Some(repr.head -> repr.tail) 
    } 
} 

और फिर सब कुछ ठीक काम करता है।

scala> val Some((c, _)) = "one".headTailOption 
c: scala.collection.generic.IsTraversableLike.stringRepr.A = o 

scala> c.isSpaceChar 
res0: Boolean = false 

संकलक जानता है कि scala.collection.generic.IsTraversableLike.stringRepr.AChar के समान है।

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