2014-04-24 7 views
11

में दृश्यों मान लीजिए कि आप तरीकों में से एक गुच्छा मिल गया है दो:उपयोग करने के लिए-समझ, कोशिश करो और स्काला

def foo() : Try[Seq[String]] 
def bar(s:String) : Try[String] 

और आप बनाना चाहते एक के लिए-comprhension:

for { 
    list <- foo 
    item <- list 
    result <- bar(item) 
} yield result 
निश्चित रूप से

यह संकलित नहीं होगा क्योंकि इस संदर्भ में प्रयास के साथ सेक का उपयोग नहीं किया जा सकता है।

किसी के पास एक अच्छा समाधान है कि इसे अलग-अलग दो में तोड़ने के बिना यह साफ कैसे लिखना है?

मैं तीसरे समय के लिए इस वाक्यविन्यास समस्या में आया हूं और सोचा कि यह इसके बारे में पूछने का समय है।

+0

यह भी देखें http://stackoverflow.com/q/4719592/298389 –

उत्तर

3

IMHO:

पुस्तकालय के लिए कोड::

case class trySeq[R](run : Try[Seq[R]]) { 
    def map[B](f : R => B): trySeq[B] = trySeq(run map { _ map f }) 
    def flatMap[B](f : R => trySeq[B]): trySeq[B] = trySeq { 
    run match { 
     case Success(s) => sequence(s map f map { _.run }).map { _.flatten } 
     case Failure(e) => Failure(e) 
    } 
    } 

    def sequence[R](seq : Seq[Try[R]]): Try[Seq[R]] = { 
    seq match { 
     case Success(h) :: tail => 
     tail.foldLeft(Try(h :: Nil)) { 
      case (Success(acc), Success(elem)) => Success(elem :: acc) 
      case (e : Failure[R], _) => e 
      case (_, Failure(e)) => Failure(e) 
     } 
     case Failure(e) :: _ => Failure(e) 
     case Nil => Try { Nil } 
    } 
    } 
} 

object trySeq { 
    def withTry[R](run : Seq[R]): trySeq[R] = new trySeq(Try { run }) 
    def withSeq[R](run : Try[R]): trySeq[R] = new trySeq(run map (_ :: Nil)) 

    implicit def toTrySeqT[R](run : Try[Seq[R]]) = trySeq(run) 
    implicit def fromTrySeqT[R](trySeqT : trySeq[R]) = trySeqT.run 
} 

और आप के लिए-comrehension बस का उपयोग कर सकते हैं (के बाद और Seq प्रयास करें क्या आप एक इकाई ट्रांसफार्मर परिभाषित करने की जरूरत की तुलना में अधिक है अपने पुस्तकालय आयात):

def foo : Try[Seq[String]] = Try { List("hello", "world") } 
def bar(s : String) : Try[String] = Try { s + "! " } 

val x = for { 
    item1 <- trySeq { foo } 
    item2 <- trySeq { foo } 
    result <- trySeq.withSeq { bar(item2) } 
} yield item1 + result 

println(x.run) 

और इसके लिए काम करता है:

def foo() = Try { List("hello", throw new IllegalArgumentException()) } 
// x = Failure(java.lang.IllegalArgumentException) 
+0

मुझे अपने गले में महसूस हो रहा था कि इसे किसी प्रकार के मोनड-जादू के साथ करना है। मुझे इस सामान को सीखने में कुछ समय बिताना होगा। वास्तव में फायदेमंद लगता है। – almendar

2

ए प्रयास को एक विकल्प में परिवर्तित किया जा सकता है, जिसे आप समझने के लिए उपयोग कर सकते हैं। जैसे

scala> def testIt() = { 
    | val dividend = Try(Console.readLine("Enter an Int that you'd like to divide:\n").toInt) 
    | dividend.toOption 
    | } 
testIt:()Option[Int] 

scala> for (x <- testIt()) println (x * x) 
Enter an Int that you'd like to divide: 

scala> for (x <- testIt()) println (x * x) 
Enter an Int that you'd like to divide: 
1522756 

पहली बार मैं "डब्ल्यू" में प्रवेश किया, तो दूसरी बार 1234

+0

कोशिश करने के लिए अलबो का उपयोग करने की कोशिश करें। लेकिन इसे सेक्लाइक के साथ मिश्रित नहीं किया जा सकता है।समस्या यह है कि टाइप मिस मैच होगा क्योंकि इसकी आवश्यकता होगी [...] और SeqLike मिलेगा। – almendar

+0

"चेतावनी: कक्षा में पढ़ा गया तरीका डिलीकेटेड कंसोल को हटा दिया गया है: scala.io.StdIn में विधि का उपयोग करें। –

3

आप तथ्य यह है कि TryOptionSeq को Option में बदला जा सकता है, और का लाभ ले सकते हैं:

for { 
    list <- foo.toOption.toSeq // toSeq needed here, as otherwise Option.flatMap will be used, rather than Seq.flatMap 
    item <- list 
    result <- bar(item).toOption // toSeq not needed here (but allowed), as it is implicitly converted 
} yield result 

यह एक (संभावित रूप से खाली होगा, अगर Try एस विफल हो जाएगा) Seq

यदि आप सभी अपवाद विवरण रखना चाहते हैं, तो आपको Try[Seq[Try[String]]] की आवश्यकता होगी। यह समझ के लिए एक एकल के साथ नहीं किया जा सकता है, तो आप सादे map साथ चिपके हुए सबसे अच्छा कर रहे हैं:

foo map {_ map bar} 

आप एक अलग तरह से अपने Try और Seq रों आपस में मिलना चाहते हैं, बातें fiddlier, के रूप में मिलता है Try[Seq[Try[String]]] को फ़्लैट करने का कोई प्राकृतिक तरीका नहीं है। @ युरी का जवाब उस चीज को दिखाता है जो आपको करना है।

या, यदि आप केवल अपने कोड के दुष्प्रभाव में रुचि रखते हैं, तो आप सिर्फ कर सकते हैं:

for { 
    list <- foo 
    item <- list 
    result <- bar(item) 
} result 

यह काम करता है क्योंकि foreach एक कम प्रतिबंधक प्रकार हस्ताक्षर हैं।

+0

समस्या यह है कि मैं अपवाद विवरण खो दूंगा। मैं जो हासिल करना चाहता हूं वह है सेक के सभी तत्वों को संसाधित करना और रोकना अगर कोई अपवाद फेंक देगा। विकल्प के साथ विचार के लिए धन्यवाद के अलावा। एक अच्छी चाल – almendar

+1

मैंने उन विकल्पों के बारे में थोड़ी सी चर्चा के साथ अद्यतन किया है जो अपवाद विवरण रखते हैं। –

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