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
( isDefinedAt
yö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. res0
bir(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 = List
ve map
yö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 F
bir functor ise ve bir fonksiyonumuz A => B
varsa, bir fonksiyonumuz varF[A] => F[B]
. lift
Yö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]