2012-09-03 9 views
19

मेरे पास एक प्ले है! 2 स्कैला एप्लिकेशन के लिए जो बाहरी सेवा से जेएसओएन प्रारूप में कुछ डेटा पुनर्प्राप्त करने की आवश्यकता है।क्या मोनैड ट्रांसफार्मर सेवाओं से जेएसओएन प्राप्त करने के लिए आवेदन करते हैं?

Play! फ्रेमवर्क Promise में प्रतिक्रिया को लपेटकर HTTP अनुरोधों को असीमित रूप से करने की अनुमति देता है। Promise एक मोनैड है जो एक मूल्य को लपेटता है जो भविष्य में उपलब्ध होगा।

यह ठीक है, लेकिन मेरे मामले में जो मुझे वेब सेवा से मिलता है वह एक JSON स्ट्रिंग है। मुझे इसे पार्स करना होगा और पार्सिंग असफल हो सकती है। इसलिए मुझे Option में जो भी मिलता है उसे लपेटना होगा। नतीजा यह है कि मेरी कई विधियां Promise[Option[Whatever]] लौट रही हैं। यही है, Whatever प्रकार का मान जो बाद में उपलब्ध होगा।

अब जब भी मुझे इस तरह के मूल्य पर काम करना पड़ता है तो मुझे इसे दो बार map की आवश्यकता होती है। मैं निम्नलिखित तरीके से इस से निपटने में सोच रहा था:

  • एक नए प्रकार बनाने, Hope[A] कहते हैं, कि एक Promise[Option[A]]
  • (map तरह प्रासंगिक तरीकों को परिभाषित करने या शायद मैं foreach का उपयोग करें और कुछ संग्रह से विरासत चाहिए लपेटता विशेषता?) और flatten
  • Promise[Option[A]] और Hope[A] के बीच एक अंतर्निहित कनवर्टर प्रदान करते हैं।

यह map परिभाषित करने के लिए आसान है - दो functors की रचना फिर से एक functor है - और flatten इस मामले में स्पष्ट रूप से किया जा सकता है, या जब भी Option के साथ एक इकाई रचना।

लेकिन यह मेरी सीमित समझ है कि मुझे इस सामग्री को फिर से शुरू करने की आवश्यकता नहीं है: मोनाड ट्रांसफॉर्मर बिल्कुल इस मामले के लिए मौजूद है। या, ठीक है, तो मुझे लगता है - मैंने कभी भी एक मोनड ट्रैनफॉर्मर का उपयोग नहीं किया है - और यह प्रश्न का बिंदु है:

क्या इस स्थिति में मोनड ट्रैनफॉर्मर्स का उपयोग किया जा सकता है? मैं वास्तव में उनका उपयोग करने के बारे में कैसे जाउंगा?

उत्तर

15

Scalaz लाइब्रेरी की OptionT ट्रांसफार्मर का उपयोग करके आप करने के लिए सक्षम होना चाहिए:

ठीक है, तो आप बस यहाँ scalaz.OptionT उपयोग कर सकते हैं OptionT[Promise, A] प्रकार के मानों में Promise[Option[A]] के मानों को चालू करें।

Scalaz 7 का उपयोग करना:

import scalaz.OptionT._ 
val x: OptionT[Promise, Int] = optionT(Promise.pure(Some(123))) 

उदाहरण उस पर map या flatMap कॉल करने के लिए इस मान का उपयोग करने के लिए, आप के लिए Promise (Functormap के लिए, flatMap के लिए Monad) एक उपयुक्त typeclass प्रदान करने के लिए की आवश्यकता होगी।

चूंकि Promise मोनैडिक है, तो Monad[Promise] का उदाहरण प्रदान करना संभव होना चाहिए। (आप Functor और मुक्त करने के लिए Applicative मिलेगा, क्योंकि typeclasses एक वंशानुगत पदानुक्रम के रूप में।) उदाहरण के लिए (ध्यान दें: मैं इस परीक्षण नहीं किया गया है!):

implicit val promiseMonad = new Monad[Promise] { 
    def point[A](a: => A): Promise[A] = Promise.pure(a) 
    def bind[A, B](fa: Promise[A])(f: A => Promise[B]): Promise[B] = fa flatMap f 
} 

एक साधारण उदाहरण के रूप में, आप अब उपयोग कर सकते हैं mapOptionT[Promise, A] पर, अंदर मान के प्रकार A => B के एक समारोह को लागू करने के:

def foo[A, B](x: OptionT[Promise, A], f: A => B): OptionT[Promise, B] = x map f 

एक OptionT[Promise, A] से अंतर्निहित Promise[Option[A]] मान प्राप्त करने के लिए, run विधि कॉल।

def bar[A, B](x: Promise[Option[A]], f: A => B): Promise[Option[B]] = 
    optionT(x).map(f).run 

आप इकाई ट्रांसफार्मर का उपयोग कर जब आप संगत प्रकार के कई आपरेशनों रचना कर सकते हैं आपरेशन के बीच OptionT[Promise, _] प्रकार के संरक्षण और अंत में अंतर्निहित मान पुन: प्राप्त करने से अधिक लाभ प्राप्त होगा।

एक समझ में परिचालन लिखने के लिए, आपको A => OptionT[Promise, B] प्रकार के कार्यों की आवश्यकता होगी।

+0

धन्यवाद, ऐसा लगता है कि यह वही है जो मुझे चाहिए! – Andrea

+0

मैंने कोशिश की है और सब कुछ मेरे आवेदन में ठीक काम करता है। केवल एक अजीब चीज है: यदि मैं अपने कार्यों के रिटर्न प्रकार को सरल बनाने के लिए एक प्रकार उपनाम 'प्रकार आशा [ए] = वादा [विकल्प [ए]]' पेश करता हूं, तो मुझे एक संकलन-समय त्रुटि मिलती है 'java.lang.IllegalArgumentException : हस्तांतरण के लिए सभी संग्रहों के समान आकार की आवश्यकता होती है। क्या आपके पास कोई सुराग है? – Andrea

+0

@Andrea: यदि आप 'विकल्प टी' के साथ एक स्पष्ट प्रकार पैरामीटर का उपयोग करते हैं तो त्रुटि दूर होनी चाहिए। यह एक कंपाइलर बग की तरह दिखता है और यदि आपके पास समय है [समस्या ट्रैकर] (https://issues.scala-lang.org/secure/Dashboard.jspa) की जांच करना या यहां एक फॉलो-अप प्रश्न पूछना उचित हो सकता है। –

1

- हटाया -

संपादित करें:

val x = optionT(Promise { /* api call */ some("""{ "foo": "bar" }""") }) 
val mapped = x.map(Json.parse).run // run return the resulting Promise[Option[T]] 
+0

ठीक है, आपकी चार पंक्तियों के बजाय 'x map (_ * 2)' लिखने में। अब, इस छोटे से उदाहरण में यह बहुत कम मूल्य हो सकता है, लेकिन अधिक जटिल मामलों में मुझे लगता है कि यह मामलों को और स्पष्ट कर सकता है। – Andrea

+0

ने मेरा उत्तर – drexin

+0

अपडेट किया है यह समझ संकलित नहीं होगी क्योंकि 'x' और' opt' संगत प्रकारों के नहीं हैं। आपको समझ के लिए दो घोंसले की आवश्यकता होगी। –

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

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