टीएल; डीआर सीधे अंतिम उदाहरण पर जाते हैं
मैं कोशिश करूँगा और फिर से तैयार करूँगा।
परिभाषाएं
forसमझ गठबंधन करने के लिए एक वाक्य रचना शॉर्टकट है flatMapऔर mapएक तरह से पढ़ सकते हैं और के बारे में कारण आसान है कि में।
चलिए चीजों को थोड़ा सरल करते हैं और मान लेते हैं कि प्रत्येक classजो दोनों पूर्वोक्त विधियों को प्रदान करता है उसे एक कहा जा सकता है monadऔर हम एक आंतरिक प्रकार के साथ प्रतीक M[A]का उपयोग करेंगे ।monadA
उदाहरण
कुछ आम तौर पर देखे जाने वाले मठों में शामिल हैं:
List[String] कहाँ पे
M[X] = List[X]
A = String
Option[Int] कहाँ पे
Future[String => Boolean] कहाँ पे
M[X] = Future[X]
A = (String => Boolean)
नक्शा और फ्लैटपाइप
एक सामान्य मठ में परिभाषित किया गया M[A]
def map(f: A => B): M[B]
def flatMap(f: A => M[B]): M[B]
जैसे
val list = List("neo", "smith", "trinity")
val f: String => List[Int] = s => s.map(_.toInt).toList
list map f
>> List(List(110, 101, 111), List(115, 109, 105, 116, 104), List(116, 114, 105, 110, 105, 116, 121))
list flatMap f
>> List(110, 101, 111, 115, 109, 105, 116, 104, 116, 114, 105, 110, 105, 116, 121)
अभिव्यक्ति के लिए
<-प्रतीक का उपयोग करने वाले अभिव्यक्ति में प्रत्येक पंक्ति को एक flatMapकॉल में अनुवादित किया जाता है , अंतिम पंक्ति को छोड़कर जो एक समापन mapकॉल के लिए अनुवादित होता है , जहां बाईं ओर के "बाध्य प्रतीक" को तर्क फ़ंक्शन के पैरामीटर के रूप में पारित किया जाता है (क्या हमने पहले कहा जाता है f: A => M[B]:
for {
bound <- list
out <- f(bound)
} yield out
list.flatMap { bound =>
f(bound).map { out =>
out
}
}
list.flatMap { bound =>
f(bound)
}
list flatMap f
केवल एक के साथ एक अभिव्यक्ति को तर्क के रूप में पारित अभिव्यक्ति के साथ कॉल <-में बदल mapदिया जाता है:
for {
bound <- list
} yield f(bound)
list.map { bound =>
f(bound)
}
list map f
अब बात है
जैसा कि आप देख सकते हैं, mapऑपरेशन मूल के "आकार" को संरक्षित करता है monad, इसलिए yieldअभिव्यक्ति के लिए भी ऐसा ही होता है : एक Listअवशेष Listजो ऑपरेशन में परिवर्तित सामग्री के साथ रहता है yield।
दूसरी ओर प्रत्येक बंधन रेखा forक्रमिक की एक रचना है monads, जिसे "एकल आकार" बनाए रखने के लिए "चपटा" होना चाहिए।
एक पल के लिए मान लें कि प्रत्येक आंतरिक बंधन को एक mapकॉल में अनुवादित किया गया था , लेकिन दाहिने हाथ एक ही A => M[B]कार्य था, आप M[M[B]]समझ में प्रत्येक पंक्ति के लिए समाप्त हो जाएंगे ।
पूरे forसिंटैक्स का आशय आसानी से क्रमिक "मोनडिक शेप" में एक मूल्य को "लिफ्ट" करना है, जो कि "मोनैडिक शेप" में एक मूल्य को "उठाता है" A => M[B]), एक अंतिम mapऑपरेशन के अतिरिक्त जो संभवतः एक समापन परिवर्तन होता है।
मुझे आशा है कि यह अनुवाद की पसंद के पीछे के तर्क की व्याख्या करता है, जो एक यांत्रिक तरीके से लागू होता है, वह है: n flatMapनेस्टेड कॉल एक एकल mapकॉल द्वारा संपन्न ।
वाक्यविन्यास
की स्पष्टता दिखाने के लिए एक आकस्मिक उदाहरण उदाहरण हैfor
case class Customer(value: Int)
case class Consultant(portfolio: List[Customer])
case class Branch(consultants: List[Consultant])
case class Company(branches: List[Branch])
def getCompanyValue(company: Company): Int = {
val valuesList = for {
branch <- company.branches
consultant <- branch.consultants
customer <- consultant.portfolio
} yield (customer.value)
valuesList reduce (_ + _)
}
क्या आप इसके प्रकार का अनुमान लगा सकते हैं valuesList?
जैसा कि पहले ही कहा गया है, monadसमझ का आकार बनाए रखा जाता है, इसलिए हम एक Listमें शुरू करते हैं company.branches, और एक के साथ समाप्त होना चाहिए List।
इसके बजाय आंतरिक प्रकार बदलता है और yieldअभिव्यक्ति द्वारा निर्धारित किया जाता है: जो हैcustomer.value: Int
valueList होना चाहिए एक List[Int]