2012-08-14 18 views

उत्तर

32

इकाई ट्रांसफार्मर बारे

यह एक बहुत ही संक्षिप्त परिचय है। आपको haskellwiki या यह great slide by @jrwest पर अधिक जानकारी मिल सकती है।

monads रचना नहीं है, जिसका अर्थ है कि यदि आप एक इकाई A[_] और एक इकाई B[_] है, तो A[B[_]]स्वचालित रूप से प्राप्त नहीं किया जा सकता है। हालांकि ज्यादातर मामलों में यह किसी दिए गए मोनड के लिए तथाकथित मोनैड ट्रांसफार्मर प्राप्त करके हासिल किया जा सकता है।

हम इकाई B के लिए इकाई ट्रांसफार्मर BT है, तो हम एक नया इकाई A[B[_]]किसी भी इकाईA के लिए रचना कर सकते हैं। यह सही है, BT का उपयोग करके, हम BA के अंदर डाल सकते हैं। scalaz

निम्नलिखित scalaz 7 मानता में

इकाई ट्रांसफार्मर के उपयोग, के बाद से स्पष्ट रूप से मैं scalaz 6 साथ इकाई ट्रांसफार्मर का उपयोग नहीं किया।

एक मोनड ट्रांसफॉर्मर MT दो प्रकार के पैरामीटर लेता है, पहला रैपर (बाहरी) मोनैड होता है, दूसरा मोनैड स्टैक के नीचे वास्तविक डेटा प्रकार होता है। नोट: इसमें अधिक प्रकार के पैरामीटर लग सकते हैं, लेकिन वे ट्रांसफॉर्मर-नेस से संबंधित नहीं हैं, बल्कि उस दिए गए मोनड के लिए विशिष्ट हैं (जैसे Writer के लॉग प्रकार, या Validation के त्रुटि प्रकार)।

तो यदि हमारे पास List[Option[A]] है जो हम एक बना मोनाड के रूप में व्यवहार करना चाहते हैं, तो हमें OptionT[List, A] की आवश्यकता है। अगर हमारे पास Option[List[A]] है, तो हमें ListT[Option, A] की आवश्यकता है।

वहां कैसे पहुंचे? यदि हमारे पास गैर-ट्रांसफॉर्मर मान है, तो हम आमतौर पर ट्रांसफॉर्मर के अंदर मान प्राप्त करने के लिए इसे MT.apply से लपेट सकते हैं। रूपांतरित रूप से सामान्य से वापस पाने के लिए, हम आम तौर पर परिवर्तित मूल्य पर .run पर कॉल करते हैं।

तो val a: OptionT[List, Int] = OptionT[List, Int](List(some(1)) और val b: List[Option[Int]] = a.run समान डेटा हैं, केवल प्रतिनिधित्व अलग है।

यह टोनी मॉरिस द्वारा सुझाया गया था जो जितनी जल्दी हो सके परिवर्तित संस्करण में जाने के लिए सबसे अच्छा है और जितना संभव हो सके इसका उपयोग करें।

नोट: ट्रांसफॉर्मर का उपयोग करके एकाधिक मोनैड लिखना सामान्य ट्रांसफ़ॉर्मर स्टैक को सामान्य डेटा प्रकार के विपरीत क्रम के साथ उत्पन्न करता है। तो एक सामान्य List[Option[Validation[E, A]]] तरह type ListOptionValidation[+E, +A] = ValidationT[({type l[+a] = OptionT[List, a]})#l, E, A]

अद्यतन कुछ ऐसा दिखाई देगा: scalaz के रूप में 7.0.0-M2, Validation (सही) एक इकाई नहीं है और इसलिए ValidationT मौजूद नहीं है। इसके बजाय EitherT का उपयोग करें।

अपनी जरूरत के आधार पर प्रवेश करने के लिए WriterT उपयोग करके, आप (पृष्ठभूमि में इस मामले में यह Id इकाई जो कुछ नहीं करता उपयोग किया जाएगा) किसी विशेष बाहरी इकाई के बिना WriterT उपयोग कर सकते हैं , या लॉगिंग को एक मोनैड के अंदर रख सकते हैं, या लॉगिंग के अंदर एक मोनड डाल सकते हैं।

पहला मामला, सरल प्रवेश

import scalaz.{Writer} 
import scalaz.std.list.listMonoid 
import scalaz._ 

def calc1 = Writer(List("doing calc"), 11) 
def calc2 = Writer(List("doing other"), 22) 

val r = for { 
    a <- calc1 
    b <- calc2 
} yield { 
    a + b 
} 

r.run should be_== (List("doing calc", "doing other"), 33) 

हम listMonoid उदाहरण आयात करते हैं, क्योंकि यह भी Semigroup[List] उदाहरण प्रदान करता है। यह जरूरत के बाद से WriterT क्रम लॉग मूल्यों गठबंधन करने के लिए सक्षम होने के लिए एक semigroup होने के लिए लॉग प्रकार की जरूरत है।

दूसरा मामला, एक इकाई

यहाँ के अंदर प्रवेश करने हम सादगी के लिए Option इकाई चुना है।

import scalaz.{Writer, WriterT} 
import scalaz.std.list.listMonoid 
import scalaz.std.option.optionInstance 
import scalaz.syntax.pointed._ 

def calc1 = WriterT((List("doing calc") -> 11).point[Option]) 
def calc2 = WriterT((List("doing other") -> 22).point[Option]) 

val r = for { 
    a <- calc1 
    b <- calc2 
} yield { 
    a + b 
} 

r.run should be_== (Some(List("doing calc", "doing other"), 33)) 
इस दृष्टिकोण के साथ

, के बाद से प्रवेश Option इकाई के अंदर है, अगर बाध्य विकल्पों में से किसी None है, हम सिर्फ एक None परिणाम कोई लॉग बिना मिलेगा।

नोट: x.point[Option]Some(x) के समान ही है, लेकिन कोड को बेहतर बनाने में मदद कर सकता है। घातक नहीं, अभी अभी तक ऐसा ही किया है।

तीसरा विकल्प, एक इकाई

import scalaz.{Writer, OptionT} 
import scalaz.std.list.listMonoid 
import scalaz.std.option.optionInstance 
import scalaz.syntax.pointed._ 

type Logger[+A] = WriterT[scalaz.Id.Id, List[String], A] 

def calc1 = OptionT[Logger, Int](Writer(List("doing calc"), Some(11): Option[Int])) 
def calc2 = OptionT[Logger, Int](Writer(List("doing other"), None: Option[Int])) 

val r = for { 
    a <- calc1 
    b <- calc2 
} yield { 
    a + b 
} 

r.run.run should be_== (List("doing calc", "doing other") -> None) 

के बाहर प्रवेश करने यहाँ हम Writer अंदर Option इकाई लगाने के लिए OptionT का उपयोग करें। गणना में से एक पता चलता है कि यहां तक ​​कि इस मामले में लॉग संरक्षित कर रहे हैं None है।

अंतिम टिप्पणी

इन उदाहरणों List[String] में लॉग प्रकार के रूप में इस्तेमाल किया गया था। हालांकि String का उपयोग कर शायद ही कभी सबसे अच्छा तरीका है बस कुछ सम्मेलन प्रवेश चौखटे से हम पर मजबूर कर दिया है। उदाहरण के लिए कस्टम लॉग एडीटी को परिभाषित करना बेहतर होगा, और आउटपुट के लिए आवश्यक होने पर, इसे यथासंभव देर तक स्ट्रिंग में परिवर्तित करें। इस तरह से आप लॉग के एडीटी को क्रमानुसार और बाद में आसानी से प्रोग्राम के रूप में यह विश्लेषण कर सकता है (बजाय तार पार्स करने की)।

WriterT उपयोगी तरीकों में से एक मेजबान के प्रवेश को कम करने, स्रोत की जाँच के साथ काम करने की है। एक w: WriterT[...] दिए गए उदाहरण के लिए, आप w :++> List("other event") उपयोग कर एक नया लॉग प्रविष्टि जोड़ने के लिए, या यहाँ तक कि वर्तमान में आयोजित मूल्य w :++>> ((v) => List("the result is " + v)) का उपयोग कर, आदि का उपयोग कर लॉग इन कर सकते

कई स्पष्ट और दीर्घाकार कोड (प्रकार, कॉल) उदाहरण में हैं। हमेशा के रूप में, ये स्पष्टता के लिए हैं, सामान्य प्रकार और ओप निकालने के द्वारा उन्हें अपने कोड में दोबारा दोहराएं।

+0

नोट: स्केलज़-सात हेड में आगामी 'मोनाडवाइटर' टाइपक्लास है। इस पर नजर रखने के लायक है। – ron

+0

https: // github देखें।com/scalaz/scalaz/pull/128 – ron

0
type OptionLogger[A] = WriterT[Option, NonEmptyList[String], A] 

     val two: OptionLogger[Int] = WriterT.put(2.some)("The number two".pure[NonEmptyList]) 
     val hundred: OptionLogger[Int] = WriterT.put(100.some)("One hundred".pure[NonEmptyList]) 

     val twoHundred = for { 
     a <- two 
     b <- hundred 
     } yield a * b 

     twoHundred.value must be equalTo(200.some) 


     val log = twoHundred.written map { _.list } getOrElse List() mkString(" ") 
     log must be equalTo("The number two One hundred") 
+1

मुझे इसे गिस्ट के रूप में देखने को याद है (@puffnfresh द्वारा ट्वीट किया गया) https://gist.github.com/3345722 – ron

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

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