Scala Language
Currying
खोज…
वाक्य - विन्यास
- एफ़ंक्शन (10) _ // '_' का उपयोग करके संकलक को बताता है कि बाकी के सभी पैरामीटर समूह के सभी मापदंडों पर अंकुश लगाया जाएगा।
- nArityFunction.curried // एक समान करी संस्करण के लिए n-arity फ़ंक्शन देता है
- दूसरा फंक्शन (x) (_: स्ट्रिंग) (z) // एक मनमाना पैरामीटर करी। इसे स्पष्ट रूप से अपने प्रकार की आवश्यकता है।
एक संरूपित फ़ंक्शन के रूप में एक विन्यास योग्य गुणक
def multiply(factor: Int)(numberToBeMultiplied: Int): Int = factor * numberToBeMultiplied
val multiplyBy3 = multiply(3)_ // resulting function signature Int => Int
val multiplyBy10 = multiply(10)_ // resulting function signature Int => Int
val sixFromCurriedCall = multiplyBy3(2) //6
val sixFromFullCall = multiply(3)(2) //6
val fortyFromCurriedCall = multiplyBy10(4) //40
val fortyFromFullCall = multiply(10)(4) //40
विभिन्न प्रकार के कई पैरामीटर समूह, मनमाने पदों के करीने मापदंडों
def numberOrCharacterSwitch(toggleNumber: Boolean)(number: Int)(character: Char): String =
if (toggleNumber) number.toString else character.toString
// need to explicitly specify the type of the parameter to be curried
// resulting function signature Boolean => String
val switchBetween3AndE = numberOrCharacterSwitch(_: Boolean)(3)('E')
switchBetween3AndE(true) // "3"
switchBetween3AndE(false) // "E"
एकल पैरामीटर समूह के साथ एक फ़ंक्शन को करी करना
def minus(left: Int, right: Int) = left - right
val numberMinus5 = minus(_: Int, 5)
val fiveMinusNumber = minus(5, _: Int)
numberMinus5(7) // 2
fiveMinusNumber(7) // -2
Currying
चलो 2 तर्कों के एक कार्य को परिभाषित करते हैं:
def add: (Int, Int) => Int = (x,y) => x + y val three = add(1,2)
करी add
इसे एक फंक्शन में बदल दिया जाता है जो एक Int
लेता है और एक फ़ंक्शन ( एक Int
से एक Int
) लौटाता है
val addCurried: (Int) => (Int => Int) = add2.curried // ^~~ take *one* Int // ^~~~ return a *function* from Int to Int val add1: Int => Int = addCurried(1) val three: Int = add1(2) val allInOneGo: Int = addCurried(1)(2)
आप इस अवधारणा को किसी भी फ़ंक्शन पर लागू कर सकते हैं जो कई तर्क लेता है। एक फ़ंक्शन को ले जाना, जो कई तर्क लेता है, इसे एक तर्क लेने वाले कार्यों के अनुप्रयोगों की एक श्रृंखला में बदल देता है:
def add3: (Int, Int, Int) => Int = (a,b,c) => a + b + c + d def add3Curr: Int => (Int => (Int => Int)) = add3.curried val x = add3Curr(1)(2)(42)
Currying
करीपिंग, विकिपीडिया के अनुसार,
एक फ़ंक्शन के मूल्यांकन का अनुवाद करने की तकनीक है जो कार्यों के अनुक्रम के मूल्यांकन में कई तर्क लेती है।
इसके विपरीत, दो प्रकार के तर्क लेने वाले किसी फ़ंक्शन के संदर्भ में, स्केला प्रकारों के संदर्भ में, (यह 2 है)
val f: (A, B) => C // a function that takes two arguments of type `A` and `B` respectively
// and returns a value of type `C`
सेवा
val curriedF: A => B => C // a function that take an argument of type `A`
// and returns *a function*
// that takes an argument of type `B` and returns a `C`
तो arity-2 कार्यों के लिए हम करी फंक्शन को इस प्रकार लिख सकते हैं:
def curry[A, B, C](f: (A, B) => C): A => B => C = {
(a: A) => (b: B) => f(a, b)
}
उपयोग:
val f: (String, Int) => Double = {(_, _) => 1.0}
val curriedF: String => Int => Double = curry(f)
f("a", 1) // => 1.0
curriedF("a")(1) // => 1.0
स्काला हमें कुछ भाषा सुविधाएँ देता है जो इसकी सहायता करती हैं:
- आप करी कार्यों को विधियों के रूप में लिख सकते हैं। इसलिए
curriedF
रूप में लिखा जा सकता है:
def curriedFAsAMethod(str: String)(int: Int): Double = 1.0
val curriedF = curriedFAsAMethod _
- आप एक मानक पुस्तकालय विधि का उपयोग करके अन-करी (यानी
A => B => C
से(A, B) => C
) पर जा सकते हैं:Function.uncurried
val f: (String, Int) => Double = Function.uncurried(curriedF)
f("a", 1) // => 1.0
कब करें करी का इस्तेमाल
करीकरण एक फ़ंक्शन के मूल्यांकन का अनुवाद करने की तकनीक है जो कार्यों के अनुक्रम के मूल्यांकन में कई तर्क लेती है, प्रत्येक एक तर्क के साथ ।
उदाहरण के लिए यह सामान्य रूप से उपयोगी है:
- किसी फ़ंक्शन के विभिन्न तर्कों की गणना अलग-अलग समय पर की जाती है । (उदाहरण 1)
- फ़ंक्शन के विभिन्न तर्कों को एप्लिकेशन के विभिन्न स्तरों द्वारा गणना की जाती है । (उदाहरण 2)
उदाहरण 1
मान लेते हैं कि कुल वार्षिक आय आय और एक बोनस से बना एक फ़ंक्शन है:
val totalYearlyIncome:(Int,Int) => Int = (income, bonus) => income + bonus
उपरोक्त 2-एरिटी फ़ंक्शन का करी संस्करण है:
val totalYearlyIncomeCurried: Int => Int => Int = totalYearlyIncome.curried
उपरोक्त परिभाषा में ध्यान दें कि प्रकार को भी देखा जा सकता है / जैसा लिखा जा सकता है:
Int => (Int => Int)
मान लेते हैं कि वार्षिक आय भाग अग्रिम में जाना जाता है:
val partialTotalYearlyIncome: Int => Int = totalYearlyIncomeCurried(10000)
और नीचे कुछ बिंदु पर बोनस ज्ञात है:
partialTotalYearlyIncome(100)
उदाहरण 2
मान लेते हैं कि कार निर्माण में कार के पहियों और कार बॉडी का अनुप्रयोग शामिल है:
val carManufacturing:(String,String) => String = (wheels, body) => wheels + body
इन भागों को विभिन्न कारखानों द्वारा लागू किया जाता है:
class CarWheelsFactory {
def applyCarWheels(carManufacturing:(String,String) => String): String => String =
carManufacturing.curried("applied wheels..")
}
class CarBodyFactory {
def applyCarBody(partialCarWithWheels: String => String): String = partialCarWithWheels("applied car body..")
}
ध्यान दें कि ऊपर CarWheelsFactory
कार निर्माण कार्य को पूरा करता है और केवल पहियों को लागू करता है।
कार निर्माण की प्रक्रिया तब निम्न रूप लेगी:
val carWheelsFactory = new CarWheelsFactory()
val carBodyFactory = new CarBodyFactory()
val carManufacturing:(String,String) => String = (wheels, body) => wheels + body
val partialCarWheelsApplied: String => String = carWheelsFactory.applyCarWheels(carManufacturing)
val carCompleted = carBodyFactory.applyCarBody(partialCarWheelsApplied)
करी का वास्तविक विश्व उपयोग।
हमारे पास क्रेडिट कार्ड की एक सूची है और हम उन सभी कार्डों के लिए प्रीमियम की गणना करना चाहते हैं जिन्हें क्रेडिट कार्ड कंपनी को भुगतान करना है। प्रीमियम स्वयं क्रेडिट कार्ड की कुल संख्या पर निर्भर करते हैं, ताकि कंपनी उन्हें तदनुसार समायोजित कर सके।
हमारे पास पहले से ही एक फ़ंक्शन है जो एकल क्रेडिट कार्ड के लिए प्रीमियम की गणना करता है और कंपनी द्वारा जारी किए गए कुल कार्ड को ध्यान में रखता है:
case class CreditCard(creditInfo: CreditCardInfo, issuer: Person, account: Account)
object CreditCard {
def getPremium(totalCards: Int, creditCard: CreditCard): Double = { ... }
}
अब इस समस्या का एक उचित तरीका यह होगा कि प्रत्येक क्रेडिट कार्ड को एक प्रीमियम में मैप किया जाए और इसे एक राशि तक कम किया जाए। कुछ इस तरह:
val creditCards: List[CreditCard] = getCreditCards()
val allPremiums = creditCards.map(CreditCard.getPremium).sum //type mismatch; found : (Int, CreditCard) ⇒ Double required: CreditCard ⇒ ?
हालांकि कंपाइलर को यह पसंद नहीं है, क्योंकि CreditCard.getPremium
को दो मापदंडों की आवश्यकता होती है। बचाव के लिए आंशिक आवेदन! हम आंशिक रूप से क्रेडिट कार्ड की कुल संख्या को लागू कर सकते हैं और उस फ़ंक्शन का उपयोग क्रेडिट कार्ड को उनके प्रीमियम पर मैप करने के लिए कर सकते हैं। हम सभी को कई पैरामीटर सूचियों का उपयोग करने के लिए इसे बदलकर getPremium
फ़ंक्शन को getPremium
ज़रूरत है और हम जाने के लिए अच्छे हैं।
परिणाम कुछ इस तरह दिखना चाहिए:
object CreditCard {
def getPremium(totalCards: Int)(creditCard: CreditCard): Double = { ... }
}
val creditCards: List[CreditCard] = getCreditCards()
val getPremiumWithTotal = CreditCard.getPremium(creditCards.length)_
val allPremiums = creditCards.map(getPremiumWithTotal).sum