Scala'da “kaldırma” nedir?


253

Bazen Scala ekosistemindeki makaleleri okuduğumda "kaldırma" / "kaldırma" terimini okuyorum. Ne yazık ki, bunun tam olarak ne anlama geldiği açıklanmıyor. Biraz araştırma yaptım ve kaldırmanın fonksiyonel değerlerle veya bunun gibi bir şeyle ilgisi var gibi görünüyor, ancak kaldırmanın başlangıçta ne anlama geldiğini açıklayan bir metin bulamadım.

Lift çerçevesinde, adında kaldırma olan ek karışıklıklar var , ancak sorunun yanıtlanmasına yardımcı olmuyor.

Scala'da "kaldırma" nedir?

Yanıtlar:


290

Birkaç kullanım vardır:

PartialFunction

PartialFunction[A, B]A'nın, alanın bazı alt kümeleri için tanımlanmış bir işlev olduğunu unutmayın A( isDefinedAtyöntem tarafından belirtildiği gibi ). A'yı " PartialFunction[A, B]içine " kaldırabilirsiniz Function[A, Option[B]]. Bu, üzerinde tanımlanan bir fonksiyonudur bütün arasında A, ancak, değerleri tiptedirOption[B]

Bu yöntemin açık çağırma yapılır liftüzerinde 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)

Yöntemler

Bir yöntem çağırma işlemini bir işleve "kaldırabilirsiniz". Buna eta-genişleme denir (bunun için Ben James'e teşekkürler). Yani mesela:

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

Alt çizgiyi uygulayarak bir yöntemi bir işleve kaldırıyoruz

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

scala> f(4)
res0: Int = 8

Yöntemler ve fonksiyonlar arasındaki temel farka dikkat edin. res0bir(işlev) türünün örneğidir (yani bir değerdir )(Int => Int)

functors

Bir functor ( scalaz tarafından tanımlandığı gibi ) bir "konteyner" dir (terimi çok gevşek kullanırım), Föyle ki, eğer bir F[A]ve fonksiyonumuz varsaA => B , o zaman ellerimizi bir F[B](örneğin, düşünün F = Listve mapyöntem )

Bu özelliği şu şekilde kodlayabiliriz:

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

Bu, işlevi "kaldırabilmek" için izomorfiktir A => B etki alanına . Yani:

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

Yani, eğer Fbir functor ise ve bir fonksiyonumuz A => Bvarsa, bir fonksiyonumuz varF[A] => F[B] . liftYöntemi deneyebilir ve uygulayabilirsiniz - bu oldukça önemsizdir.

Monad Transformatörleri

As hcoopz altına diyor (ve sadece bu gereksiz kod bir ton yazma kurtardı beni olurdu fark ettik) terimi, "asansör" da içinde anlamlıdır Monad Transformers . Bir monad transformatörünün, monadları üst üste "istiflemenin" bir yolu olduğunu hatırlayın (monadlar oluşturmaz).

Örneğin, bir döndüren fonksiyonunuz olduğunu varsayın IO[Stream[A]]. Bu monad transformatörüne dönüştürülebilir StreamT[IO, A]. Şimdi IO[B]belki de bu bir başka değeri "kaldırmak" isteyebilirsiniz StreamT. Bunu şu şekilde yazabilirsiniz:

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

Veya bu:

iob.liftM[StreamT]

: Bu soruyu yalvarır neden bir dönüştürmek istiyorsun IO[B]bir içine StreamT[IO, B]? . Cevap "kompozisyon olanaklarından yararlanmak" olacaktır. Diyelim ki bir fonksiyonunuz varf: (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
"Bir metodun bir fonksiyona kaldırılması" na genellikle eta-genişleme denir .
Ben James

7
Skalaya daha da derinlemesine bakıldığında , kaldırma da monad transformatörlerine göre ortaya çıkar . Bir varsa MonadTransörneği Tiçin Mve Monadiçin örneği N, daha sonra T.liftMkullanılabilir asansör türünde bir değer N[A]türünde bir değere M[N, A].
846846846

Teşekkürler Ben, hcoopz. Cevabı değiştirdim
oxbow_lakes

Mükemmel! Söylemek için sadece bir neden daha var: Scala - en iyisi. Hangi Martin Odersky & Co - en iyi kaldırılabilir. Bunun için bile kullanıyordum liftM, ancak bunu nasıl doğru bir şekilde yapacağımı anlamadı. Beyler, sen harikasın!
Dmitry Bespalov

3
In Yöntemleri bölümünde ... res0 bir örnek (fonksiyonu) türü (Int => Int) arasında (yani bu bir değerdir) 'dir ... Meli değil f, bir örneği olmayan olmak res0?
srzhio

21

Bir başka kullanım kaldırma gazetelerde rastlamak ettik (ille Scala-ilişkili olanlar) bir işlevi aşırı yüklüyor f: A -> Bile f: List[A] -> List[B](ya setleri, MULTISETS, ...). Bu genellikle formalizasyonları basitleştirmek için kullanılır, çünkü daha sonra ftek bir elemana mı yoksa birden fazla elemana mı uygulandığı önemli değildir .

Bu tür aşırı yükleme genellikle bildirici olarak yapılır, örn.

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

veya

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

veya zorunlu olarak, ör.

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

5
Bu, oxbow_lakes'in tarif ettiği "functor'a kaldırma" dır.
Ben James

7
@BenJames Gerçekten de. Benim savunmam için: oxbow_lakes cevabı henüz benimkini yazmaya başladığımda yoktu.
Malte Schwerhoff

20

PartialFunction[Int, A]Uzanan (oxbow_lakes tarafından işaret edildiği gibi) herhangi bir koleksiyonun kaldırılabileceğine dikkat edin; böylece örneğin

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

bu, kısmi bir işlevi, koleksiyonda tanımlı olmayan değerlerin eşlendiği toplam bir işleve dönüştürür None,

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

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

Dahası,

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

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

Bu sınır dışı istisnaları endeks önlemek için düzgün bir yaklaşım gösterir .


6

Ayrıca can sıkıcı kaldırılmasına ters süreçtir.

Kaldırma,

kısmi bir fonksiyonun PartialFunction[A, B]toplam fonksiyona dönüştürülmesiA => Option[B]

o zaman kaldırma

toplam işlevi A => Option[B]kısmi işleve dönüştürme PartialFunction[A, B]

Scala standart kütüphane tanımlar Function.unliftolarak

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

Örneğin, play-json kütüphanesi JSON serileştiricilerinin inşasına yardımcı olmak için kaldırma sağlar :

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))
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.