टीएल; डीआर सीधे अंतिम उदाहरण पर जाते हैं
मैं कोशिश करूँगा और फिर से तैयार करूँगा।
परिभाषाएं
for
समझ गठबंधन करने के लिए एक वाक्य रचना शॉर्टकट है flatMap
और map
एक तरह से पढ़ सकते हैं और के बारे में कारण आसान है कि में।
चलिए चीजों को थोड़ा सरल करते हैं और मान लेते हैं कि प्रत्येक class
जो दोनों पूर्वोक्त विधियों को प्रदान करता है उसे एक कहा जा सकता है monad
और हम एक आंतरिक प्रकार के साथ प्रतीक M[A]
का उपयोग करेंगे ।monad
A
उदाहरण
कुछ आम तौर पर देखे जाने वाले मठों में शामिल हैं:
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]