2009-07-28 12 views
46

Option मोनैड स्केल में कुछ या कुछ भी चीज़ों से निपटने का एक शानदार अभिव्यक्तिपूर्ण तरीका है। लेकिन अगर "कुछ भी नहीं" होने पर किसी को संदेश लॉग करने की आवश्यकता होती है तो क्या होगा? स्काला API दस्तावेज़ के अनुसार,स्कैला कोड

या तो प्रकार अक्सर scala.Option के लिए एक विकल्प जहां वाम विफलता का प्रतिनिधित्व करता है (प्रथा के अनुसार) और सही कुछ के लिए समान है के रूप में प्रयोग किया जाता है।

हालांकि, मुझे असफल प्रसंस्करण के लिए या तो या तो अच्छे या वास्तविक वास्तविक दुनिया के उदाहरणों का उपयोग करके सर्वोत्तम प्रथाओं को खोजने का कोई भाग्य नहीं था।

def logs: Array[String] = { 
     def props: Option[Map[String, Any]] = configAdmin.map{ ca => 
      val config = ca.getConfiguration(PID, null) 
      config.properties getOrElse immutable.Map.empty 
     } 
     def checkType(any: Any): Option[Array[String]] = any match { 
      case a: Array[String] => Some(a) 
      case _ => None 
     } 
     def lookup: Either[(Symbol, String), Array[String]] = 
      for {val properties <- props.toRight('warning -> "ConfigurationAdmin service not bound").right 
       val logsParam <- properties.get("logs").toRight('debug -> "'logs' not defined in the configuration").right 
       val array <- checkType(logsParam).toRight('warning -> "unknown type of 'logs' confguration parameter").right} 
      yield array 

     lookup.fold(failure => { failure match { 
      case ('warning, msg) => log(LogService.WARNING, msg) 
      case ('debug, msg) => log(LogService.DEBUG, msg) 
      case _ => 
     }; new Array[String](0) }, success => success) 
    } 

(कृपया ध्यान दें यह एक वास्तविक परियोजना से एक टुकड़ा है, इसलिए यह अपने आप ही संकलन नहीं होगा)

मैं था: अंत में मैं अपने ही परियोजना के लिए निम्न कोड के साथ आए हैं यह जानने के लिए आभारी रहें कि आप अपने कोड में Either का उपयोग कैसे कर रहे हैं और/या उपर्युक्त कोड को पुन: सक्रिय करने के बेहतर विचारों का उपयोग कर रहे हैं।

+1

मैं का कोई जिक्र नहीं मिल सकता है ओडर्सकी की किताब में जो भी हो, वह भी। – skaffman

+4

हां, मेरे पास "स्कैला में प्रोग्रामिंग" है और इसमें कोई भी उल्लेख नहीं मिला। सबसे अच्छा सादृश्य मुझे पता है कि लिफ्टवेब में बॉक्स है जिसका उपयोग विफलताओं को ले जाने के उद्देश्य से भी किया जाता है - यह विकल्प की तरह है, लेकिन अतिरिक्त कार्यक्षमता के साथ। –

+0

'विकल्प [या तो [फू, बार]]' के लिए कोई बेहतर विकल्प? – Jus12

उत्तर

44

या तो संभवतः दो अर्थपूर्ण परिणामों में से एक को वापस करने के लिए उपयोग किया जाता है, विकल्प के विपरीत जो एक सार्थक परिणाम या कुछ भी वापस करने के लिए उपयोग नहीं किया जाता है।

एक आसान उदाहरण समझने के लिए नीचे दी गई है (स्काला मेलिंग सूची थोड़ी देर के पीठ पर परिचालित):

def throwableToLeft[T](block: => T): Either[java.lang.Throwable, T] = 
    try { 
    Right(block) 
    } catch { 
    case ex => Left(ex) 
    } 

के रूप में समारोह नाम का तात्पर्य, अगर "ब्लॉक" के निष्पादन सफल होता है, यह वापस आ जाएगी "दाएं (< परिणाम>)"। अन्यथा, अगर एक थ्रोबल फेंक दिया जाता है, तो यह वापस आ जाएगा "बाएं (< फेंकने योग्य>)"। परिणाम संसाधित करने के लिए मिलान पैटर्न का उपयोग करें:

var s = "hello" 
throwableToLeft { s.toUpperCase } match { 
    case Right(s) => println(s) 
    case Left(e) => e.printStackTrace 
} 
// prints "HELLO" 

s = null 
throwableToLeft { s.toUpperCase } match { 
    case Right(s) => println(s) 
    case Left(e) => e.printStackTrace 
} 
// prints NullPointerException stack trace 

आशा है कि मदद करता है।

+5

पिकुलियर ... क्यों न केवल अपवाद फेंक? – skaffman

+10

पूरे स्थान पर अपवाद हैंडलिंग कोड होने के कारण बदसूरत और प्रबंधन करना मुश्किल है। फेंकने योग्य टॉलेट का उपयोग पैटर्न मिलान में अपवाद हैंडलिंग का उपयोग करता है, जो इमो, पढ़ने और बनाए रखने में आसान है। –

+24

उदाहरण के लिए, आपके पास कई कलाकार अलग-अलग गणना कर सकते हैं, जिनमें से कुछ वास्तव में परिणाम लौटाते हैं, और कुछ अपवाद फेंकते हैं। यदि आप अपवाद फेंकते हैं, तो उनमें से कुछ कलाकारों ने अभी तक काम करना शुरू नहीं किया हो सकता है, आप किसी भी अभिनेता के परिणाम खो देते हैं जिन्होंने अभी तक समाप्त नहीं किया है, आदि। इस दृष्टिकोण के साथ, सभी कलाकार एक मूल्य (कुछ 'वाम', कुछ वापस कर देंगे 'दाएं') और यह संभालने के लिए बहुत आसान हो जाता है। –

6

आपके द्वारा पोस्ट किया गया स्निपेट बहुत ही प्रतीत होता है। आप किसी ऐसी स्थिति में उपयोग करते हैं जहां:

  1. यह जानने के लिए पर्याप्त नहीं है कि डेटा उपलब्ध नहीं है।
  2. आपको दो अलग-अलग प्रकारों में से एक को वापस करने की आवश्यकता है।

बाएं में अपवाद को चालू करना वास्तव में एक सामान्य उपयोग केस है। प्रयास/पकड़ने पर, इसे कोड को एक साथ रखने का लाभ होता है, जो अपवाद अपेक्षित परिणाम है, तो यह समझ में आता है। जब यह एक संग्रह में प्रकट होता है

result match { 
    case Right(res) => ... 
    case Left(res) => ... 
} 

Either से निपटने में एक और दिलचस्प तरीका है: से निपटने या तो का सबसे आम तरीका पैटर्न मिलान है। संग्रह पर नक्शा करते समय, अपवाद फेंकना व्यवहार्य नहीं हो सकता है, और आप "संभव नहीं" के अलावा कुछ जानकारी वापस लौटना चाह सकते हैं। एक या तो का उपयोग करके आप ऐसा करने के लिए एल्गोरिथ्म overburdening बिना सक्षम बनाता है:

val list = (
    library 
    \\ "books" 
    map (book => 
    if (book \ "author" isEmpty) 
     Left(book) 
    else 
     Right((book \ "author" toList) map (_ text)) 
) 
) 

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

val authorCount = (
    (Map[String,Int]() /: (list filter (_ isRight) map (_.right.get))) 
    ((map, author) => map + (author -> (map.getOrElse(author, 0) + 1))) 
    toList 
) 
val problemBooks = list flatMap (_.left.toSeq) // thanks to Azarov for this variation 

तो, मूल या तो उपयोग ऐसा ही होता है। यह एक विशेष रूप से उपयोगी वर्ग नहीं है, लेकिन अगर आप इसे पहले देख चुके थे। दूसरी तरफ, यह बेकार नहीं है।

+0

सूची flatMap {_.left.toSeq} एक ही समस्या वापस करने के लिए लगता है किताबें, है ना? –

+0

हाँ, यह होगा। मुझे पता था कि इसमें एक फ्लैटमैप चाल थी, लेकिन जब मैंने उदाहरण लिखा था तो मुझे यह नहीं मिला। –

12

स्कालज़ लाइब्रेरी में कुछ समान नाम है या तो सत्यापन नाम दिया गया है। यह या तो "वैध परिणाम या विफलता" के रूप में उपयोग के लिए या तो अधिक मूर्खतापूर्ण है।

सत्यापन भी त्रुटियों को जमा करने की अनुमति देता है।

संपादित करें: "समान" या तो पूरी तरह से झूठा है, क्योंकि प्रमाणीकरण एक आवेदक मज़ेदार है, और स्केलज़ या तो नाम दिया गया है \/(उच्चारण "विघटन" या "या तो"), एक मोनड है। तथ्य यह है कि सत्यापन उस प्रकृति के कारण त्रुटियों को जमा कर सकता है। दूसरी तरफ,/"प्रारंभिक" प्रकृति है, पहले पर रोक रहा है - \/(इसे "बाएं" या "त्रुटि" पढ़ें) यह मुठभेड़ करता है। यहां एक आदर्श विवरण है: http://typelevel.org/blog/2014/02/21/error-handling.html

देखें: http://scalaz.googlecode.com/svn/continuous/latest/browse.sxr/scalaz/example/ExampleValidation.scala.html

टिप्पणी, कॉपी/ऊपर के लिंक का पेस्ट द्वारा अनुरोध के रूप में (कुछ पंक्तियाँ हटा दिया):

// Extracting success or failure values 
val s: Validation[String, Int] = 1.success 
val f: Validation[String, Int] = "error".fail 

// It is recommended to use fold rather than pattern matching: 
val result: String = s.fold(e => "got error: " + e, s => "got success: " + s.toString) 

s match { 
    case Success(a) => "success" 
    case Failure(e) => "fail" 
} 

// Validation is a Monad, and can be used in for comprehensions. 
val k1 = for { 
    i <- s 
    j <- s 
} yield i + j 
k1.toOption assert_≟ Some(2) 

// The first failing sub-computation fails the entire computation. 
val k2 = for { 
    i <- f 
    j <- f 
} yield i + j 
k2.fail.toOption assert_≟ Some("error") 

// Validation is also an Applicative Functor, if the type of the error side of the validation is a Semigroup. 
// A number of computations are tried. If the all success, a function can combine them into a Success. If any 
// of them fails, the individual errors are accumulated. 

// Use the NonEmptyList semigroup to accumulate errors using the Validation Applicative Functor. 
val k4 = (fNel <**> fNel){ _ + _ } 
k4.fail.toOption assert_≟ some(nel1("error", "error")) 
+2

उत्तर में यहां एक उदाहरण देखना अच्छा लगेगा। प्रश्न में उठाए गए समस्याओं के प्रकार के लिए लागू। –

+0

'flatMap', और इस प्रकार 'सत्यापन' पर समझ के लिए स्केलज़ 7.1 में बहिष्कृत किया गया है और स्केलज़ 7.1 में हटा दिया गया है। उत्तर में उदाहरण अब काम नहीं करते हैं। [बहिष्करण चर्चा] देखें (https://groups.google.com/forum/#!topic/scalaz/Wnkdyhebo2w) – kostja