Є кілька звичаїв:
Частковефункція
Запам'ятати a PartialFunction[A, B]
- це функція, визначена для деякого підмножини домену A
(як визначено isDefinedAt
методом). Ви можете "підняти" a PartialFunction[A, B]
в a 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)
Функціонери
Функтор (як визначено 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]