एक पूरा काम कर उदाहरण के लिए कुछ सरल परिभाषाएँ:
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
type User = String
type Location = String
type Address = String
case class UserProfile(user: User, location: Location, addresses: Address)
def getUserById(id: Long): Future[Option[User]] = id match {
case 1 => Future.successful(Some("Foo McBar"))
case _ => Future.successful(None)
}
def getLocationById(id: Long): Future[Option[Location]] = id match {
case 1 => Future.successful(Some("The Moon"))
case _ => Future.successful(None)
}
def getAddressById(id: Long): Future[Option[Address]] = id match {
case 1 => Future.successful(Some("123 Moon St."))
case _ => Future.successful(None)
}
और पूर्णता के लिए के लिए, यहाँ क्या Scalaz मुक्त कार्यान्वयन इस तरह दिखाई देगा:
def getProfile(uid: Long, lid: Long, aid: Long): Future[Option[UserProfile]] =
for {
maybeUser <- getUserById(uid)
maybeLocation <- getLocationById(lid)
maybeAddress <- getAddressById(aid)
} yield (
for {
user <- maybeUser
location <- maybeLocation
address <- maybeAddress
} yield UserProfile(user, location, address)
)
अर्थात हमें समझने के लिए घोंसला करना है, जैसे कि हमें map
को घूमने के लिए घोंसला करना होगा उदा। Int
मान जो Future[Option[Int]]
के अंदर हो सकता है।
OptionT
स्कालाज़ या बिल्लियों में मोनैड ट्रांसफार्मर आपको इस घोंसले के बिना Future[Option[A]]
जैसे प्रकारों के साथ काम करने की अनुमति देने के लिए डिज़ाइन किया गया है। उदाहरण के लिए आप इस लिख सकते हैं:
import scalaz.OptionT, scalaz.std.scalaFuture._
def getProfile(uid: Long, lid: Long, aid: Long): OptionT[Future, UserProfile] =
for {
user <- OptionT(getUserById(uid))
location <- OptionT(getLocationById(lid))
address <- OptionT(getAddressById(aid))
} yield UserProfile(user, location, address)
या यदि आप एक Future[Option[UserProfile]]
चाहता था तुम सिर्फ run
कॉल कर सकते हैं:
def getProfile(uid: Long, lid: Long, aid: Long): Future[Option[UserProfile]] = (
for {
user <- OptionT(getUserById(uid))
location <- OptionT(getLocationById(lid))
address <- OptionT(getAddressById(aid))
} yield UserProfile(user, location, address)
).run
और फिर:
scala> getProfile(1L, 1L, 1L).foreach(println)
Some(UserProfile(Foo McBar,The Moon,123 Moon St.))
तो मध्यवर्ती परिणाम के किसी भी कर रहे हैं None
, पूरी बात None
होगी:
scala> getProfile(1L, 1L, 0L).foreach(println)
None
scala> getProfile(0L, 0L, 0L).foreach(println)
None
और निश्चित रूप से यदि कोई अनुरोध विफल हो जाता है, तो पूरी चीज पहली त्रुटि के साथ विफल हो जाती है।
एक फुटनोट के रूप में, यदि अनुरोध एक दूसरे पर निर्भर नहीं है, तो आप उन्हें applicatively बजाय monadically रचना कर सकते हैं:
import scalaz.Scalaz._
def getProfile(uid: Long, lid: Long, aid: Long): Future[Option[UserProfile]] = (
OptionT(getUserById(uid)) |@|
OptionT(getLocationById(lid)) |@|
OptionT(getAddressById(aid))
)(UserProfile.apply _).run
इस मॉडल गणना अधिक सही और के बाद से चला सकते हैं और अधिक कुशल हो सकता है समानांतर में अनुरोध।
चूंकि यह स्पष्ट रूप से 'विकल्प टी' के बारे में है, हो सकता है कि इसमें 'स्केलज़' टैग (और संभवतः 'मोनैड-ट्रांसफॉर्मर्स' और/या 'स्कैला-बिल्लियों' भी हो)? –