Existem alguns usos:
PartialFunction
Lembre-se de a PartialFunction[A, B]
é uma função definida para algum subconjunto do domínio A
(conforme especificado pelo isDefinedAt
método). Você pode "elevar" a PartialFunction[A, B]
para a Function[A, Option[B]]
. Ou seja, uma função definida sobre o conjunto de A
mas cujos valores são do tipoOption[B]
Isso é feito pela invocação explícita do método 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)
Métodos
Você pode "elevar" uma chamada de método para uma função. Isso se chama eta-expansão (obrigado a Ben James por isso). Então, por exemplo:
scala> def times2(i: Int) = i * 2
times2: (i: Int)Int
Colocamos um método em uma função aplicando o sublinhado
scala> val f = times2 _
f: Int => Int = <function1>
scala> f(4)
res0: Int = 8
Observe a diferença fundamental entre métodos e funções. res0
é uma instância (ou seja, é um valor ) do tipo (função)(Int => Int)
Functors
Um functor (como definido por scalaz ) é algum "contêiner" (eu uso o termo extremamente livremente), de F
modo que, se tivermos F[A]
uma função e A => B
, então podemos colocar a mão em um F[B]
(pense, por exemplo, F = List
e no map
método )
Podemos codificar esta propriedade da seguinte maneira:
trait Functor[F[_]] {
def map[A, B](fa: F[A])(f: A => B): F[B]
}
Isso é isomórfico por poder "elevar" a função A => B
para o domínio do functor. Isso é:
def lift[F[_]: Functor, A, B](f: A => B): F[A] => F[B]
Ou seja, se F
é um functor, e temos uma função A => B
, temos uma função F[A] => F[B]
. Você pode tentar implementar o lift
método - é bastante trivial.
Monad Transformers
Como o hcoopz diz abaixo (e eu acabei de perceber que isso me salvaria de escrever uma tonelada de código desnecessário), o termo "lift" também tem um significado dentro dos Monad Transformers . Lembre-se de que os transformadores de mônada são uma maneira de "empilhar" mônadas umas sobre as outras (as mônadas não compõem).
Por exemplo, suponha que você tenha uma função que retorne um IO[Stream[A]]
. Isso pode ser convertido no transformador de mônada StreamT[IO, A]
. Agora você pode querer "elevar" algum outro valor e IO[B]
talvez também seja um StreamT
. Você pode escrever isto:
StreamT.fromStream(iob map (b => Stream(b)))
Ou isto:
iob.liftM[StreamT]
isso levanta a questão: por que eu quero converter um IO[B]
em um StreamT[IO, B]
? . A resposta seria "tirar proveito das possibilidades de composição". Digamos que você tenha uma funçãof: (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
instânciaT
paraM
e umMonad
exemplo paraN
, em seguida,T.liftM
pode ser usado para levantar um valor de tipoN[A]
para um valor do tipoM[N, A]
.liftM
para isso, mas não conseguia entender como fazer isso corretamente. Gente, você é rock!f
ser uma instância, não éres0
?Outro uso de levantamento que encontrei nos documentos (não necessariamente relacionados ao Scala) está sobrecarregando uma função
f: A -> B
comf: List[A] -> List[B]
(ou conjuntos, multisets, ...). Isso geralmente é usado para simplificar formalizações, pois não importa sef
é aplicado a um elemento individual ou a vários elementos.Esse tipo de sobrecarga geralmente é feito de forma declarativa, por exemplo,
ou
ou imperativamente, por exemplo,
fonte
Observe que qualquer coleção que se estenda
PartialFunction[Int, A]
(como indicado por oxbow_lakes) pode ser levantada; assim, por exemploque transforma uma função parcial em uma função total na qual os valores não definidos na coleção são mapeados
None
,Além disso,
Isso mostra uma abordagem elegante para evitar exceções fora dos limites do índice .
fonte
Também há o levantamento , que é o processo inverso do levantamento.
Se o levantamento for definido como
então a remoção é
A biblioteca padrão Scala define
Function.unlift
comoPor exemplo, a biblioteca play-json fornece unfift para ajudar na construção de serialisers JSON :
fonte