স্কালায় "উত্তোলন" কী?


252

কখনও কখনও আমি যখন স্কালার বাস্তুসংস্থায় নিবন্ধগুলি পড়ি তখন আমি "উত্তোলন" / "উত্তোলন" শব্দটি পড়ি। দুর্ভাগ্যক্রমে, এর সঠিক অর্থ কী তা ব্যাখ্যা করা হয়নি। আমি কিছু গবেষণা করেছি, এবং দেখে মনে হচ্ছে যে কার্যক্ষম মান বা এর মতো কিছুতে উত্তোলনের কিছু একটা রয়েছে, তবে আমি একটি পাঠ্য সন্ধান করতে সক্ষম হইনি যা লিফটিংটি কীভাবে প্রাথমিকভাবে বন্ধুত্বপূর্ণ উপায়ে হয় তা ব্যাখ্যা করে।

লিফট ফ্রেমওয়ার্কের মাধ্যমে অতিরিক্ত বিভ্রান্তি রয়েছে যা এর নামে উঠছে, তবে এটি প্রশ্নের উত্তর দিতে সহায়তা করে না।

স্কালায় "উত্তোলন" কী?

উত্তর:


290

কয়েকটি ব্যবহার রয়েছে:

PartialFunction

মনে রাখবেন একটি PartialFunction[A, B]ডোমেনের কিছু উপসেটের জন্য A( isDefinedAtপদ্ধতি দ্বারা নির্দিষ্ট হিসাবে ) সংজ্ঞায়িত করা একটি ফাংশন Remember আপনি "লিফট" একটি পারেন 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ডোমেনে ফাংশনটি "উত্তোলন" করতে সক্ষম হওয়ায় isomorphic । এটাই:

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

এটি হ'ল যদি Fকোনও ফান্টেক্টর হয় এবং আমাদের একটি ফাংশন A => Bথাকে তবে আমাদের একটি ফাংশন থাকে F[A] => F[B]। আপনি liftপদ্ধতিটি প্রয়োগ করে প্রয়োগ করতে পারেন - এটি বেশ তুচ্ছ।

মোনাড ট্রান্সফর্মারস

যেমন এইচসিওপিজ নীচে বলেছেন (এবং আমি ঠিক বুঝতে পেরেছি যে এটি আমাকে এক টন অপ্রয়োজনীয় কোড লেখার হাত থেকে বাঁচিয়েছে), মোনাড ট্রান্সফরমারগুলির মধ্যে "লিফট" শব্দটিরও একটি অর্থ রয়েছে । মনে রাখবেন যে একটি মোনাড ট্রান্সফর্মার একে অপরের শীর্ষে "স্ট্যাকিং" মোনাদগুলির একটি উপায় (মনডগুলি রচনা করে না)।

উদাহরণস্বরূপ, ধরুন আপনার একটি ফাংশন রয়েছে যা একটি প্রদান করে IO[Stream[A]]। এটি মোনাড ট্রান্সফর্মারে রূপান্তরিত হতে পারে StreamT[IO, A]। এখন আপনি "লিফট" থেকে কিছু অন্যান্য মান পারেন একটি IO[B]সম্ভবত যে এটি একটি হল StreamT। আপনি হয় এটি লিখতে পারে:

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

অথবা এটা:

iob.liftM[StreamT]

: এই প্রশ্ন begs কেন আমি একজন রূপান্তর করতে চাও 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
মধ্যে আরও delving scalaz , তুলে এছাড়াও সম্পর্ক আসে আপ একসংখ্যা ট্রান্সফরমার । যদি আমি একটি আছে MonadTransউদাহরণস্বরূপ Tজন্য Mএবং Monadজন্য উদাহরণস্বরূপ N, তারপর T.liftMব্যবহার করা যেতে পারে উত্তোলন ধরনের একটি মান N[A]ধরনের মান M[N, A]
846846846

ধন্যবাদ বেন, hcoopz। আমি উত্তরটি পরিবর্তন করেছি
অক্সবো_লাক

পারফেক্ট! আরও একটি কারণ বলার জন্য: স্কেলা - সেরা। যা মার্টিন ওডারস্কি এন্ড কো - সেরা to আমি এমনকি এটির জন্য ব্যবহার liftMকরতে চাই, তবে কীভাবে এটি সঠিকভাবে করতে হয় তা বুঝতে পারি নি। ছেলেরা, তুমি শিলা!
দিমিত্রি বেসপালভ

3
ইন পদ্ধতি অধ্যায় ... res0 একটি দৃষ্টান্ত (ফাংশন) টাইপ (int => int) (অর্থাৎ এটা একটি মান) হয় ... করা উচিত নয় fএকটি দৃষ্টান্ত হতে পারে, না res0?
শ্রিজিও

21

উত্তোলনের আরেকটি ব্যবহার যা আমি কাগজপত্রের মধ্যে এসে পৌঁছেছি (অগত্যা স্কালার সাথে সম্পর্কিত নয়) (বা সেটস, মাল্টিসেটস, ...) f: A -> Bদিয়ে কোনও ফাংশন ওভারলোড করছে f: List[A] -> List[B]। এটি প্রায়শই আনুষ্ঠানিকতা সরল করতে ব্যবহৃত হয় কারণ এটি তখন কোনও 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
এটি "একটি ফান্টচারে উঠা" যা অক্সবো_লাকগুলি বর্ণনা করে।
বেন জেমস

6
@ বেনজেমস সত্যই। আমার প্রতিরক্ষার পক্ষে: আমার লেখা শুরু করার সময় অক্সবো_লাকসের উত্তর এখনও ছিল না।
মাল্টে শোয়ারহফ

20

নোট করুন যে কোনও সংকলন প্রসারিত PartialFunction[Int, A](অক্সবো_লাক্স দ্বারা নির্দেশিত) উত্তোলন করা যেতে পারে; এই উদাহরণস্বরূপ

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

রয়েছে unlifting , যা তুলে থেকে বিপরীত প্রক্রিয়া।

উত্তোলন হিসাবে হিসাবে সংজ্ঞায়িত করা হয়

একটি আংশিক ফাংশন 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]

উদাহরণস্বরূপ, প্লে- জসন লাইব্রেরি জেএসএন সিরিয়ালিয়াস নির্মাণের ক্ষেত্রে সহায়তার জন্য লিফট সরবরাহ করে :

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))
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.