स्काला में "लिफ्टिंग" क्या है?


252

कभी-कभी जब मैं स्काला इकोसिस्टम में लेख पढ़ता हूं तो मैं "लिफ्टिंग" / "लिफ्टेड" शब्द पढ़ता हूं। दुर्भाग्य से, यह नहीं बताया गया है कि वास्तव में इसका क्या मतलब है। मैंने कुछ शोध किया, और ऐसा लगता है कि उठाने का कार्यात्मक मूल्यों के साथ कुछ करना है या ऐसा कुछ है, लेकिन मुझे एक पाठ नहीं मिल पा रहा था जो बताता है कि वास्तव में शुरुआती दोस्ताना तरीके से क्या उठाना है।

लिफ्ट फ्रेमवर्क के माध्यम से अतिरिक्त भ्रम है, जो इसके नाम पर उठा है, लेकिन यह प्रश्न का उत्तर देने में मदद नहीं करता है।

स्काला में "लिफ्टिंग" क्या है?

जवाबों:


290

कुछ उपयोग हैं:

PartialFunction

याद रखें एक PartialFunction[A, B]फ़ंक्शन डोमेन के कुछ सबसेट के लिए परिभाषित किया गया है A(जैसा कि isDefinedAtविधि द्वारा निर्दिष्ट है )। आप एक PartialFunction[A, B]में "लिफ्ट" कर सकते हैं Function[A, Option[B]]। वह है, एक ऐसा फंक्शन जिसे पूरे में परिभाषित किया गया है Aलेकिन जिसका मान प्रकार का हैOption[B]

इस विधि का स्पष्ट मंगलाचरण द्वारा किया जाता है liftपर PartialFunction

scala> val pf: PartialFunction[Int, Boolean] = { case i if i > 0 => i % 2 == 0}
pf: PartialFunction[Int,Boolean] = <function1>

scala> pf.lift
res1: Int => Option[Boolean] = <function1>

scala> res1(-1)
res2: Option[Boolean] = None

scala> res1(1)
res3: Option[Boolean] = Some(false)

तरीके

आप एक फ़ंक्शन में एक विधि मंगलाचरण "उठा" सकते हैं। इसे एटा-विस्तार कहा जाता है (इसके लिए बेन जेम्स का धन्यवाद)। उदाहरण के लिए:

scala> def times2(i: Int) = i * 2
times2: (i: Int)Int

हम अंडरस्कोर को लागू करके फ़ंक्शन में एक विधि उठाते हैं

scala> val f = times2 _
f: Int => Int = <function1>

scala> f(4)
res0: Int = 8

विधियों और कार्यों के बीच मूलभूत अंतर पर ध्यान दें। res0एक उदाहरण है (यानी यह एक मान है ) (फ़ंक्शन) प्रकार का(Int => Int)

functors

एक functor (के रूप में द्वारा परिभाषित scalaz ) कुछ "कंटेनर" (मैं शब्द का प्रयोग है अत्यंत शिथिल), Fऐसा है कि, अगर हम एक है F[A]और एक समारोह A => Bहै, तो हम अपने हाथों एक पर प्राप्त कर सकते हैं F[B](लगता है, उदाहरण के लिए, F = Listऔर mapविधि )

हम इस संपत्ति को निम्नानुसार सांकेतिक शब्दों में बदलना कर सकते हैं:

trait Functor[F[_]] { 
  def map[A, B](fa: F[A])(f: A => B): F[B]
}

यह इसोमॉर्फिक है जो फंक्शनल A => Bके डोमेन में फ़ंक्शन को "लिफ्ट" करने में सक्षम है । अर्थात्:

def lift[F[_]: Functor, A, B](f: A => B): F[A] => F[B]

यही है, अगर Fएक फ़नकार है, और हमारे पास एक फ़ंक्शन है A => B, तो हमारे पास एक फ़ंक्शन है F[A] => F[B]। आप कोशिश कर सकते हैं और liftविधि को लागू कर सकते हैं - यह बहुत तुच्छ है।

मोनाड ट्रांसफॉर्मर

जैसा कि hcoopz नीचे कहता है (और मुझे अभी पता चला है कि इससे मुझे एक टन अनावश्यक कोड लिखने से बचाया गया होगा), "लिफ्ट" शब्द का भी मोनाड ट्रांसफॉर्मर्स के भीतर एक अर्थ है । स्मरण करो कि एक भिक्षु ट्रांसफार्मर एक दूसरे के शीर्ष पर "स्टैकिंग" मठों का एक तरीका है (मठ रचना नहीं करते हैं)।

इसलिए, उदाहरण के लिए, मान लीजिए कि आपके पास एक फ़ंक्शन है जो एक रिटर्न देता है IO[Stream[A]]। इसे मोनड ट्रांसफार्मर में परिवर्तित किया जा सकता है StreamT[IO, A]। अब आप शायद कुछ और "मूल्य" उठाना IO[B]चाहते हैं कि यह भी एक है StreamT। आप इसे लिख सकते हैं:

StreamT.fromStream(iob map (b => Stream(b)))

या यह:

iob.liftM[StreamT]

यह सवाल है: क्यों मैं एक IO[B]में एक में परिवर्तित करना चाहते हैं StreamT[IO, B]? । इसका उत्तर "संरचना संभावनाओं का लाभ उठाना" होगा। मान लीजिए कि आपके पास एक फ़ंक्शन हैf: (A, B) => C

lazy val f: (A, B) => C = ???
val cs = 
  for {
    a <- as                //as is a StreamT[IO, A]
    b <- bs.liftM[StreamT] //bs was just an IO[B]
  }
  yield f(a, b)

cs.toStream //is a Stream[IO[C]], cs was a StreamT[IO, C]

12
यह ध्यान देने योग्य हो सकता है कि "फ़ंक्शन के लिए एक विधि उठाना" को अक्सर एटा-विस्तार के रूप में संदर्भित किया जाता है ।
बेन जेम्स

7
स्केलेज़ में आगे बढ़ना , मोनड ट्रांसफॉर्मर के संबंध में भी उठाना । अगर मेरे पास इसके लिए एक उदाहरण है और इसके लिए एक उदाहरण है , तो इसका उपयोग प्रकार के मूल्य को एक प्रकार के मूल्य को उठाने के लिए किया जा सकता है । MonadTransTMMonadNT.liftMN[A]M[N, A]
846846846

धन्यवाद बेन, hcoopz। मैंने उत्तर संशोधित किया है
Oxbow_lakes

उत्तम! कहने का सिर्फ एक और कारण है: स्काला - सबसे अच्छा। जो मार्टिन ओडस्स्की एंड कंपनी के लिए उठाया जा सकता है - सबसे अच्छा। मैं भी उस के लिए उपयोग करना चाहते हैं liftM, लेकिन समझ नहीं आया कि कैसे ठीक से करना है। दोस्तों, आप रॉक कर रहे हैं!
दिमित्री बेस्पालोव

3
में तरीके खंड ... res0 एक उदाहरण (समारोह) का प्रकार (इंट => इंट) की (यानी यह एक मूल्य है) है ... नहीं करना चाहिए fएक उदाहरण हो सकता है, नहीं res0?
श्रीजियो

21

का एक अन्य उपयोग उठाने कि मैं पत्र में सामना करना पड़ा (जरूरी नहीं कि स्काला संबंधित वाले) से एक समारोह के अधिक भार है f: A -> Bके साथ f: List[A] -> List[B](या सेट, multisets, ...)। यह अक्सर औपचारिकताओं को सरल बनाने के लिए उपयोग किया जाता है क्योंकि यह तब कोई फर्क नहीं पड़ता कि क्या fकिसी व्यक्तिगत तत्व या कई तत्वों पर लागू होता है।

इस तरह के ओवरलोडिंग को अक्सर घोषित किया जाता है, जैसे,

f: List[A] -> List[B]
f(xs) = f(xs(1)), f(xs(2)), ..., f(xs(n))

या

f: Set[A] -> Set[B]
f(xs) = \bigcup_{i = 1}^n f(xs(i))

या अनिवार्य रूप से, जैसे,

f: List[A] -> List[B]
f(xs) = xs map f

5
यह "एक फ़नकार में उठाना" है, जिसका वर्णन oxbow_lakes करता है।
बेन जेम्स

6
@BenJames सच में। मेरी रक्षा के लिए: oxbow_lakes 'का जवाब अभी तक नहीं था जब मैंने अपना लिखना शुरू किया था।
माल्टे श्वार्फ जूल

20

ध्यान दें कि किसी भी संग्रह का विस्तार PartialFunction[Int, A](जैसा कि oxbow_lakes द्वारा बताया गया है) उठाया जा सकता है; इस प्रकार उदाहरण के लिए

Seq(1,2,3).lift
Int => Option[Int] = <function1>

जो आंशिक फ़ंक्शन को कुल फ़ंक्शन में बदल देता है जहां संग्रह में परिभाषित मूल्यों को मैप नहीं किया जाता है None,

Seq(1,2,3).lift(2)
Option[Int] = Some(3)

Seq(1,2,3).lift(22)
Option[Int] = None

इसके अलावा,

Seq(1,2,3).lift(2).getOrElse(-1)
Int = 3

Seq(1,2,3).lift(22).getOrElse(-1)
Int = -1

यह सीमा अपवादों से बाहर सूचकांक से बचने के लिए एक साफ दृष्टिकोण दिखाता है।


6

अनलिफ्टिंग भी है , जिसे उठाने की उलटी प्रक्रिया है।

यदि उठाने को परिभाषित किया जाता है

PartialFunction[A, B]कुल फ़ंक्शन में एक आंशिक फ़ंक्शन चालू करनाA => Option[B]

उसके बाद स्थानांतरण है

कुल फ़ंक्शन A => Option[B]को आंशिक फ़ंक्शन में बदलनाPartialFunction[A, B]

स्काला मानक पुस्तकालय के Function.unliftरूप में परिभाषित करता है

def unlift[T, R](f: (T)Option[R]): PartialFunction[T, R]

उदाहरण के लिए, प्ले- जसन लाइब्रेरी , JSON धारावाहिकों के निर्माण में मदद करने के लिए असंगत प्रदान करती है :

import play.api.libs.json._
import play.api.libs.functional.syntax._

case class Location(lat: Double, long: Double)

implicit val locationWrites: Writes[Location] = (
  (JsPath \ "lat").write[Double] and
  (JsPath \ "long").write[Double]
)(unlift(Location.unapply))
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.