2010-02-26 15 views
43

'नक्शा' तत्वों की संख्या को संरक्षित करता है, इसलिए इसे टुपल पर उपयोग करना समझदार लगता है।स्कैला टुपल्स पर कार्यात्मक संयोजक का उपयोग करें?

मेरे प्रयास अब तक:

scala> (3,4).map(_*2)  
error: value map is not a member of (Int, Int) 
     (3,4).map(_*2) 
      ^
scala> (3,4).productIterator.map(_*2) 
error: value * is not a member of Any 
     (3,4).productIterator.map(_*2) 
           ^
scala> (3,4).productIterator.map(_.asInstanceOf[Int]*2) 
res4: Iterator[Int] = non-empty iterator 

scala> (3,4).productIterator.map(_.asInstanceOf[Int]*2).toList 
res5: List[Int] = List(6, 8) 

यह काफी दर्दनाक लग रहा है ... और मैं भी एक टपल करने के लिए इसे वापस बदलने की कोशिश करने के लिए शुरू नहीं किया है।
क्या मैं इसे गलत कर रहा हूं? पुस्तकालय में सुधार किया जा सकता है?

+0

ऐसा लगता है कि आप एक टुपल का उपयोग कर रहे हैं जहां आपको वास्तव में संग्रह का उपयोग करना चाहिए। इसके बजाए एक वास्तविक संग्रह वर्ग का उपयोग करने पर विचार करें - टुपल्स को एक प्रकार के संग्रह के रूप में उपयोग नहीं किया जाना चाहिए। – Jesper

+1

@ जेस्पर: मैं असहमत हूं: मैं बस उस वस्तु के संग्रह पर DRY'ly और consicely उसी ऑपरेशन को लागू करना चाहता हूं जिसका आकार स्थिर रूप से ज्ञात है। –

उत्तर

27

shapeless मानचित्रण और एक मध्यस्थ के HList प्रतिनिधित्व के माध्यम से tuples की तह का समर्थन करता है,

नमूना आरईपीएल सत्र,

scala> import shapeless._ ; import Tuples._ 
import shapeless._ 
import Tuples._ 

scala> object double extends (Int -> Int) (_*2) 
defined module double 

scala> (3, 4).hlisted.map(double).tupled 
res0: (Int, Int) = (6,8) 

कहाँ टपल के तत्वों विभिन्न प्रकार आप विशेष प्रकार के मामलों के साथ एक बहुरूपी समारोह के साथ मैप कर सकते हैं के हैं,

scala> object frob extends Poly1 { 
    | implicit def caseInt  = at[Int](_*2) 
    | implicit def caseString = at[String]("!"+_+"!") 
    | implicit def caseBoolean = at[Boolean](!_) 
    | } 
defined module frob 

scala> (23, "foo", false, "bar", 13).hlisted.map(frob).tupled 
res1: (Int, String, Boolean, String, Int) = (46,!foo!,true,!bar!,26) 

अद्यतन

tuples की निराकार 2.0.0-M1 मानचित्रण के रूप में सीधे समर्थित है। उपर्युक्त उदाहरण अब इस तरह दिखते हैं,

scala> import shapeless._, poly._, syntax.std.tuple._ 
import shapeless._ 
import poly._ 
import syntax.std.tuple._ 

scala> object double extends (Int -> Int) (_*2) 
defined module double 

scala> (3, 4) map double 
res0: (Int, Int) = (6,8) 

scala> object frob extends Poly1 { 
    | implicit def caseInt  = at[Int](_*2) 
    | implicit def caseString = at[String]("!"+_+"!") 
    | implicit def caseBoolean = at[Boolean](!_) 
    | } 
defined module frob 

scala> (23, "foo", false, "bar", 13) map frob 
res1: (Int, String, Boolean, String, Int) = (46,!foo!,true,!bar!,26) 
+0

यह बहुत अच्छा है! मैं आपके उत्तर को स्वीकार्य मानता हूं, लेकिन मुझे नहीं पता कि कई वर्षों के बाद स्वीकृत उत्तर को बदलना ठीक है या नहीं। –

+2

आपको जो भी जवाब सबसे अच्छा लगता है उसे स्वीकार करना चाहिए। यदि परिस्थितियों या आपकी राय समय के साथ बदलती है, तो मुझे लगता है कि तदनुसार आपकी स्वीकृति को अपडेट करना उचित है। –

+0

आईएमएचओ, यह सामान रास्ता बहुत सार है। मेरा मतलब है, इसे 3 पूरे नामस्थान आयात करने की आवश्यकता है (xxxxx._ आयात करें) और पूर्ण सामान्य मामले के लिए, इसे ट्यूपल्स में आइटम प्रकार के रूप में कई अतिरिक्त implicits की आवश्यकता है। यह निश्चित रूप से उपयोग के मामलों पर निर्भर करता है, लेकिन संभवतः एक सरल, स्पष्ट कोड दक्षता के नुकसान के बिना अधिक पठनीय होगा। –

35

सामान्य रूप से, ट्यूपल के तत्व प्रकार समान नहीं होते हैं, इसलिए नक्शा समझ में नहीं आता है। आप विशेष मामला संभाल करने, हालांकि एक समारोह को परिभाषित कर सकते हैं:

scala> def map[A, B](as: (A, A))(f: A => B) = 
    as match { case (a1, a2) => (f(a1), f(a2)) } 
map: [A,B](as: (A, A))(f: (A) => B)(B, B) 

scala> val p = (1, 2)  
p: (Int, Int) = (1,2) 

scala> map(p){ _ * 2 } 
res1: (Int, Int) = (2,4) 

आप p.map(_ * 2) के रूप में इस कॉल करने के लिए दलाल मेरी लाइब्रेरी पैटर्न का उपयोग कर सकते हैं।

अद्यतन

यहां तक ​​कि जब तत्वों के प्रकार ही नहीं हैं, Tuple2[A, B] एक Bifunctor, जो bimap संचालन के साथ मैप किया जा सकता है।

scala> import scalaz._ 
import scalaz._ 

scala> import Scalaz._ 
import Scalaz._ 

scala> val f = (_: Int) * 2 
f: (Int) => Int = <function1> 

scala> val g = (_: String) * 2 
g: (String) => String = <function1> 

scala> f <-: (1, "1") :-> g 
res12: (Int, String) = (2,11) 

अद्यतन 2

http://gist.github.com/454818

+0

रिकॉर्ड के लिए, मैं इस से स्वीकार्य उत्तर को बेकार पुस्तकालय के बारे में हालिया उत्तर में बदल रहा हूं, जो 2010 में वापस उपलब्ध नहीं था। –