2010-11-15 8 views
8

कहता है, मेरे पास "सत्यापन" फ़ंक्शंस का एक समूह है जो कोई त्रुटि नहीं होने पर कोई नहीं लौटाता है, अन्यथा यह त्रुटि संदेश निर्दिष्ट करने वाले कुछ (स्ट्रिंग) को वापस कर देता है। निम्नलिखित की तरह कुछ ...मैं विकल्प मोनाड के प्रवाह के विपरीत कैसे हो सकता हूं?

def validate1:Option[String] 
def validate2:Option[String] 
def validate3:Option[String] 

मैं के रूप में एक रिटर्न कुछ (स्ट्रिंग) उन्हें एक क्रम में कॉल करने के लिए जा रहा हूँ और जैसे ही, मैं बंद करो और एक ही लौट आते हैं। यदि यह कोई नहीं लौटाता है, तो अनुक्रम समाप्त होने तक मैं अगले तक जाता हूं। अगर उनमें से कोई भी वापस नहीं लौटाता है, तो मैं कोई नहीं लौटाता हूं।

मैं उन्हें "अभिव्यक्ति के लिए" में एक साथ चिपकाना चाहता हूं। कुछ ...

for(a <- validate1; b <- validate2; c <- validate3) yield None; 

हालांकि, विकल्प बिल्कुल विपरीत है जो मैं चाहता हूं। यह किसी भी पर बंद नहीं होता है और कुछ (स्ट्रिंग) के साथ चलता है।

मैं ऐसा कुछ कैसे प्राप्त कर सकता हूं?

उत्तर

2

क्या आप सिर्फ इटरेटर को एक साथ जोड़ नहीं सकते हैं और फिर पहला तत्व ले सकते हैं? कुछ की तरह:

scala> def validate1: Option[String] = {println("1"); None} 
scala> def validate2: Option[String] = {println("2"); Some("error")} 
scala> def validate3: Option[String] = {println("3"); None} 
scala> (validate1.iterator ++ validate2.iterator ++ validate3.iterator).next 
1 
2 
res5: String = error 
+0

अंतिम पंक्ति एक छोटा सा सरल किया जा सकता है: '(validate1 ++ validate2 ++ validate3) – pr1001

+2

मुझे नहीं लगता कि आप करना चाहते हैं .head' '.iterator' कॉल ड्रॉप करें - फिर आप केवल कॉलिंग विधियों के बजाय सभी वैध विधियों को कॉल करेंगे जब तक कि उनमें से कोई एक त्रुटि नहीं देता है। – Steve

+1

आह, मैं देखता हूं, बहुत स्मार्ट। – pr1001

17

आप कॉल एक साथ सिर्फ श्रृंखला सकता है विकल्प पर orElse विधि के साथ

validate1 orElse validate2 orElse validate3 

या आप कार्यों के लिए परिवर्तित कर सत्यापित करें तरीकों का एक संग्रह पर एक गुना चला सकते हैं

val vlist= List(validate1 _, validate2 _, validate3 _) 

vlist.foldLeft(None: Option[String]) {(a, b) => if (a == None) b() else a} 
+3

+1 मैं छोटे और अधिक पठनीय रूप प्राप्त करने के लिए उन दो समाधानों को भी विलय कर दूंगा: l.foldLeft (कोई नहीं: विकल्प [स्ट्रिंग]) {(ए, बी) => ए या एल्स बी()} – mcveat

+0

मुझे ऑरसे चेनिंग पसंद है । धन्यवाद डॉन। – sanjib

+0

@mcveat, यह एक अच्छा परिष्करण है, @ संजीब, यह एक अच्छा सवाल था, या ऐसा लगता है कि एसओ पर अक्सर बार-बार आते हैं। –

0

मुझे लगता है कि आपको लिफ्ट के Box का उपयोग करने से लाभ हो सकता है, जिसमें Full (यानी Some), Empty (यानी। None) और Failure (एक Empty एक कारण के साथ यह खाली है और इसे जंजीर किया जा सकता है)। डेविड पोलक के पास good blog post है जो इसे पेश करता है। यह मूल उदाहरण के अलावा कोई कम नहीं है बल्कि यह एक थोड़ा और अधिक तार्किक है मेरी राय में, एक सफल सत्यापन के परिणाम के साथ

def validate1: Box[String] 
def validate2: Box[String] 
def validate3: Box[String] 
val validation = for (
    validation1 <- validate1 ?~ "error message 1" 
    validation2 <- validate2 ?~ "error message 2" 
    validation3 <- validate3 ?~ "error message 3" 
) yield "overall success message" 

: संक्षेप में, आप कुछ इस तरह (परीक्षण नहीं) कर सकते हैं Full में और Failure में एक विफल सत्यापन।

हालांकि, हम छोटे हो सकते हैं। सबसे पहले, के बाद से हमारे सत्यापन समारोह लौट Box[String], वे Failure खुद को एस लौट सकते हैं और हम Failure को Empty को बदलने की जरूरत नहीं है अपने आप को:

val validation = for (
    validation1 <- validate1 
    validation2 <- validate2 
    validation3 <- validate3 
) yield "overall success message" 

लेकिन, Box भी एक or विधि है कि एक ही Box अगर यह रिटर्न है Full या अन्य Box है यदि यह नहीं है। यह हमें देना होगा:

वैल सत्यापन = validate1 या validate2 या validate3

हालांकि, उस लाइन पहले मान्यता सफलता, नहीं पहले विफलता पर रुकती है। यह एक और तरीका बनाने के लिए समझ में आता है जो आप चाहते हैं (शायद unless कहा जाता है?) हालांकि मैं यह नहीं कह सकता कि यह वास्तव में समझ दृष्टिकोण के मुकाबले ज्यादा उपयोगी होगा।

हालांकि, यहां एक छोटे से पुस्तकालय रोगी कि करता है यह:

scala> class Unless[T](a: Box[T]) { 
    | def unless(b: Box[T]) = { 
    | if (a.isEmpty) { a } 
    | else b 
    | } 
    | } 
defined class Unless 

scala> implicit def b2U[T](b: Box[T]): Unless[T] = new Unless(b) 
b2U: [T](b: net.liftweb.common.Box[T])Unless[T] 

scala> val a = Full("yes")          
a: net.liftweb.common.Full[java.lang.String] = Full(yes) 

scala> val b = Failure("no")          
b: net.liftweb.common.Failure = Failure(no,Empty,Empty) 

scala> val c = Full("yes2")          
c: net.liftweb.common.Full[java.lang.String] = Full(yes2) 

scala> a unless b 
res1: net.liftweb.common.Box[java.lang.String] = Failure(no,Empty,Empty) 

scala> a unless b unless c 
res2: net.liftweb.common.Box[java.lang.String] = Failure(no,Empty,Empty) 

scala> a unless c unless b 
res3: net.liftweb.common.Box[java.lang.String] = Failure(no,Empty,Empty) 

scala> a unless c 
res4: net.liftweb.common.Box[java.lang.String] = Full(yes2) 

यह एक त्वरित स्काला के प्रकार प्रणाली की मेरी समझ सीमित पर आधारित हैक है के रूप में आपको निम्न त्रुटि में देख सकते हैं:

scala> b unless a 
<console>:13: error: type mismatch; 
found : net.liftweb.common.Full[java.lang.String] 
required: net.liftweb.common.Box[T] 
     b unless a 
       ^

हालांकि, यह आपको सही रास्ते पर लाने के लिए पर्याप्त होना चाहिए।

बेशक Lift ScalaDocs पर Box पर अधिक जानकारी है।

3

scalaz लाइब्रेरी में Validation नामक एक प्रकार है जो त्रुटियों और सफलता दोनों के निर्माण के साथ कुछ अविश्वसनीय जिमनास्टिक की अनुमति देता है।

import scalaz._; import Scalaz._ 
def fooA : ValidationNEL[String, A] 
def fooB : ValidationNEL[String, B] 
def fooC : ValidationNEL[String, C] 

ये श्रृंखला के लिए अनुप्रयोगी functor के साथ कॉल एक साथ इस्तेमाल किया जा सकता है: उदाहरण के लिए, यदि आप कुछ तरीकों जो एक विफलता संदेश या कुछ सफल परिणाम (ए/बी/सी) लौट सकते हैं या तो लगता है :

(foo1 <|**|> (foo2, foo3)) match { 
    case Success((a, b, c)) => //woot 
    case Failure(msgs)  => //erk 
} 

ध्यान दें कि यदि foo1/2/3 में से किसी एक विफल रहता है, तो पूरी रचना एक गैर खाली विफलता संदेशों की सूची (नेल) के साथ विफल रहता है। यदि एक से अधिक विफल रहता है, तो आपको सभी विफलता संदेश मिलते हैं।

यह एक हत्यारा ऐप है। कैसे टो एक सफलता और विफलता के लौटने के उदाहरण इस प्रकार हैं

def foo1 : ValidationNEL[String, Int] = 1.success 
def foo2 : ValidationNEL[String, Double] = "some error msg".failNel 
संबंधित मुद्दे

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