Есть несколько способов использования:
частично определённая функция
Помните, что PartialFunction[A, B]
это функция, определенная для некоторого подмножества домена A
(как указано в isDefinedAt
методе). Вы можете «поднять» PartialFunction[A, B]
в Function[A, Option[B]]
. То есть, функция , определенная над всеми из , A
но значения которых имеют типаOption[B]
Это делается путем явного вызова метода lift
on 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)
методы
Вы можете «поднять» вызов метода в функцию. Это называется eta-extension (спасибо Бену Джеймсу за это). Так, например:
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)
ФУНКТОРЫ
Функтор (как определено 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 ниже (и я только что понял, что это избавило бы меня от написания тонны ненужного кода), термин «лифт» также имеет значение в Monad Transformers . Напомним, что монадные трансформеры являются способом «укладывания» монад друг на друга (монады не составляют).
Например, предположим, у вас есть функция, которая возвращает 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]
MonadTrans
экземплярT
дляM
иMonad
экземпляр дляN
, тоT.liftM
можно использовать для поднятия значения типаN[A]
до значения типаM[N, A]
.liftM
для этого, но не сумел понять, как это сделать правильно. Ребята, вы рок!f
быть экземпляр, не такres0
ли?Другое использование подъема, с которым я сталкивался в статьях (не обязательно связанных с Scala), - это перегрузка функции с
f: A -> B
помощьюf: List[A] -> List[B]
(или множеств, мультимножеств, ...). Это часто используется для упрощения формализации, потому что тогда не имеет значения,f
применяется ли он к отдельному элементу или к нескольким элементам.Этот вид перегрузки часто выполняется декларативно, например,
или
или обязательно, например,
источник
Обратите внимание, что любая коллекция, которая расширяется
PartialFunction[Int, A]
(как указано oxbow_lakes), может быть отменена; таким образом, напримеркоторая превращает частичную функцию в целую функцию, в которую отображаются значения, не определенные в коллекции
None
,Более того,
Это показывает аккуратный подход, чтобы избежать исключений индекса за пределами границ .
источник
Существует также подъем , который является обратным процессом для подъема.
Если лифтинг определяется как
тогда unlifting
Стандартная библиотека Scala определяет
Function.unlift
какНапример, библиотека play-json предоставляет unlift для помощи в создании сериализаторов JSON :
источник