2013-04-30 18 views
5

मैं स्कैला में वायदा करने के तरीके को सरल बनाने की कोशिश कर रहा हूं। मुझे एक बिंदु पर Future[Option[Future[Option[Boolean]] मिला लेकिन मैंने इसे और नीचे सरल बना दिया है। क्या इसे सरल बनाने का कोई बेहतर तरीका है?भविष्य [विकल्प [भविष्य [विकल्प [बूलियन]] वायदा और विकल्प सरलीकृत करना?

"विफल" का भविष्य पास करने से ऐसा करने का सबसे अच्छा तरीका प्रतीत नहीं होता है। यानी अनुक्रमिक दुनिया में मैं बस "असफल !!" लौटा किसी भी समय यह अंत तक जारी रखने के बजाय विफल रहा। क्या अन्य तरीके हैं?

val doSimpleWork = Future { 
    //Do any arbitrary work (can be a different function) 
    true //or false 
} 

val doComplexWork = Future { 
    //Do any arbitrary work (can be a different function) 
    Some("result") //or false 
} 

val failed = Future { 
    //Do no work at all!!! Just return 
    false 
} 

val fut1 = doSimpleWork 
val fut2 = doSimpleWork 

val fut3 = (fut1 zip fut2).map({ 
    case (true, true) => true 
    case _ => false 
}) 

val fut4 = fut3.flatMap({ 
    case true => 
    doComplexWork.flatMap({ 
     case Some("result") => 
     doSimpleWork 
     case None => 
     failed 
    }) 
    case false => 
    failed 
}) 

fut4.map({ 
    case true => 
    "SUCCESS!!!" 
    case _ => 
    "FAIL!!" 
}) 
+0

मुझे लगता है कि आपका त्रुटि तर्क अत्यधिक जटिल हो गया है। इस स्निपेट में विफलता को संभालने के 3 संभावित तरीके हैं: असफल वायदा, विकल्प, बूलियन। मैं इस स्थिति को पहले चरण के रूप में सरल बनाने का सुझाव दूंगा, शायद अलग-अलग विफलताओं को एक पसंदीदा रूप में परिवर्तित कर सकता हूं (उदाहरण के लिए केवल भविष्य में असफल परिणाम)। –

उत्तर

3

ध्यान रखें कि आपके उदाहरण में, क्योंकि आप बेसब्री से एक val करने के लिए Futures instantiating कर रहे हैं, उन सभी को क्रियान्वित करने जैसे ही आप उन्हें (val x = Future {...}) की घोषणा के रूप में शुरू कर देंगे। इसके बजाय विधियों का उपयोग करने से फ्यूचर्स निष्पादन की श्रृंखला द्वारा अनुरोध किए जाने पर ही निष्पादित हो जाएंगे।

एक तरह से आगे गणना से बचने के लिए onFailure साथ, एक अपवाद फेंकने के लिए तो इसे संभाल होगा:

def one = future { println("one") ; Some(1) } 
def two = future { println("two") ; throw new Exception("no!"); 2 } 
def three = future { println("three") ; 3 } 

val f = one flatMap { 
    result1 => two flatMap { 
    result2 => three 
    } 
} 

f onFailure { 
    case e: Exception => 
    println("failed somewhere in the chain") 
} 

आप यहाँ देख सकते हैं कि "तीन" बाहर मुद्रित करने के लिए माना जाता है, क्योंकि हम two पर असफल। यह मामला है:

one 
two 
failed somewhere in the chain 
+0

मुझे नहीं पता था कि 'वैल एक्स = भविष्य {...}' वास्तव में इसे तुरंत चालू किया गया .. एक फ़ंक्शन को परिभाषित करना एक महान युक्ति है !!! मैं त्रुटि को कैप्चर करने के लिए 'ऑनफेलर' या 'फॉलबैक टू' का उपयोग करने जा रहा हूं। धन्यवाद! –

1

आप कुछ इस तरह की कोशिश कर सकते, comprehensions के लिए उपयोग कर एक बिट कोड को साफ करने के:

def doSimpleWork = Future{ 
    //do some simple work 
    true 
    } 

    def doComplexWork = Future{ 
    //do something complex here 
    Some("result") 
    } 

    val fut1 = doSimpleWork 
    val fut2 = doSimpleWork 

    val fut = for{ 
    f1Result <- fut1 
    f2Result <- fut2 
    if (f1Result && f2Result) 
    f3Result <- doComplexWork 
    if (f3Result.isDefined) 
    f4Result <- doSimpleWork 
    } yield "success" 

    fut onComplete{ 
    case Success(value) => println("I succeeded") 
    case Failure(ex) => println("I failed: " + ex.getMessage) 
    } 

और तुम वास्तव में सिर्फ "सफलता" प्रिंट आउट करना चाहते थे या अंत में "विफल", आप कोड के अंतिम भाग को बदल सकते हैं:

fut.recover{case ex => "failed"} onSuccess{ 
    case value => println(value) 
    } 

अब, यह बताने के लिए कि क्या हो रहा है। शुरुआत के लिए, हमने दो कार्यों को परिभाषित किया है जो Futures लौटाते हैं जो कुछ एसिंक काम कर रहे हैं। DoSimpleWork फ़ंक्शन कुछ सरल काम करेगा और एक बुलियन सफलता/असफल संकेतक लौटाएगा। DoComplexWork फ़ंक्शन कुछ और जटिल (और समय लेने वाला) करेगा और एक परिणाम [स्ट्रिंग] परिणाम का प्रतिनिधित्व करेगा। हम समझने के लिए प्रवेश करने से पहले doSimpleWork के दो समांतर आमंत्रणों को लात मारते हैं। कॉम्प के लिए, हम fut1 और fut2 (उस क्रम में) के परिणाम प्राप्त करने से पहले यह जांचने से पहले कि वे दोनों सफल थे या नहीं। यदि नहीं, तो हम यहां रुकेंगे, और fut वैल NoSuchElementException के साथ असफल हो जाएगा, जो आपको तब मिलती है जब इस तरह की स्थिति कंप के लिए विफल हो जाती है। यदि दोनों सफल होते, तो हम जारी रखते हैं और doComplexWork फ़ंक्शन का आह्वान करते हैं और इसके परिणाम की प्रतीक्षा करते हैं। इसके बाद हम इसके परिणाम की जांच करेंगे और यदि यह Some था, तो हम doSimpleWork के आखिरी आमंत्रण को बंद कर देंगे। यदि यह सफल होता है, तो हम स्ट्रिंग "सफलता" उत्पन्न करेंगे। यदि आप fut वैल के प्रकार की जांच करते हैं, तो इसका प्रकार Future[String] है।

वहाँ से, हम अगर कॉल की पूरे अनुक्रम या तो यह सभी तरह के माध्यम से (Success मामले) बनाया है, या प्रक्रिया में कहीं विफल (Failure मामले) की जांच करने, बाहर मुद्रण async कॉलबैक कार्यों में से एक का उपयोग करें कुछ मामले से संबंधित कुछ संबंधित। वैकल्पिक अंतिम कोड ब्लॉक में, हम स्ट्रिंग "असफल" लौटकर किसी भी संभावित विफलता से पुनर्प्राप्त होते हैं और फिर onSuccess कॉलबैक का उपयोग करते हैं जो कि "सफलता" या "विफल" प्रिंट करेगा जो कि हुआ था।

+0

'के लिए' का उपयोग करना अच्छा विचार है। मैं 'फ़िल्टर' का प्रयास कर रहा था लेकिन 'for'' ने उन्हें बनाया है। धन्यवाद। –

3

एक " मोनाड ट्रांसफॉर्मर "एक ऐसा निर्माण है जो आपको दो मोनैड के" प्रभाव "को गठबंधन करने देता है, स्कालज़ प्रोजेक्ट कई अलग-अलग मोनड ट्रांसफार्मर प्रदान करता है।मेरा सुझाव यह है कि आप अपने कोड को सरल बनाने के लिए ऑप्शन टी मोनैड ट्रांसफार्मर का उपयोग कर सकते हैं यदि आप इस तथ्य का भी उपयोग करते हैं कि Option[Unit] बूलियन (Some(()) == true और None == false) के लिए isomorphic है। यहां एक पूर्ण उदाहरण दिया गया है:

import scalaz._ 
import Scalaz._ 
import scala.concurrent._ 
import ExecutionContext.Implicits.global 
import scala.concurrent.duration._ 
object Foo { 

    // We need a Monad instance for Future, here is a valid one, or you can use the implementation 
    // in the scalaz-contrib project, see http://typelevel.org 
    implicit def futureMonad(implicit executor: ExecutionContext): Monad[Future] = new Monad[Future] { 
    override def bind[A, B](fa: Future[A])(f: A ⇒ Future[B]) = fa flatMap f 
    override def point[A](a: ⇒ A) = Future(a) 
    override def map[A, B](fa: Future[A])(f: A ⇒ B) = fa map f 
    } 

    // OptionT allows you to combine the effects of the Future and Option monads 
    // to more easily work with a Future[Option[A]] 
    val doSimpleWork : OptionT[Future,Unit] = OptionT(Future { 
    // Option[Unit] is isomorphic to Boolean 
    Some(()) //or None 
    }) 

    val simpleFail : OptionT[Future,Unit] = OptionT(Future { 
    None 
    }) 

    val doComplexWork: OptionT[Future,String] = OptionT(Future { 
    Some("result") //or None 
    }) 

    val f1 = doSimpleWork 
    val f2 = doSimpleWork 
    val f3 = doComplexWork 
    val f4 = doSimpleWork 

    def main(argv: Array[String]) { 
    val result = for { 
     _ <- f1 
     // we don't get here unless both the future succeeded and the result was Some 
     _ <- f2 
     _ <- f3 
     r <- f4 
    } yield(r) 

    result.fold((_ => println("SUCCESS!!")),println("FAIL!!")) 

    // "run" will get you to the Future inside the OptionT 
    Await.result(result.run, 1 second) 
    } 
} 
+0

यह वास्तव में साफ और दिलचस्प है। धन्यवाद –

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