Levantamiento en Scala

Suraj P 30 enero 2023
  1. Transformar métodos en funciones
  2. Transforme funciones puras en funtores en Scala
  3. Transformar funciones parciales a funciones en Scala
  4. Transformadores de mónadas en Scala
  5. Conclusión
Levantamiento en Scala

Este artículo hablará sobre el levantamiento en el lenguaje de programación Scala. El levantamiento tiene diferentes significados; depende del contexto en que lo usemos.

Veámoslos uno por uno.

Transformar métodos en funciones

A veces nos encontramos con situaciones en las que queremos transformar métodos en funciones. Este es un ejemplo de levantamiento.

Por ejemplo, digamos que tenemos los siguientes métodos:

def mul(x: Int) = x*5
def isEven(x: Int) = x%2==0

Ahora, podemos componer estos métodos de la siguiente manera:

isEven(mul(4))

Pero, ¿y si queremos que esta composición suceda de manera funcional? Luego tenemos que transformar estos métodos anteriores en funciones.

Eso se puede hacer levantándolos usando el símbolo _ en Scala.

val mulAns = mul _
val isEvenAns = isEven _

Ahora, podemos componerlos funcionalmente de la siguiente manera:

( mulAns andThen isEvenAns)(5)

Código de trabajo completo:

object MyClass {
    def mul(x: Int) = x*5
    def isEven(x: Int) = x%2==0

    def main(args: Array[String])
    {
        println(isEven(mul(4)));

        val mulAns = mul _
        val isEvenAns = isEven _

        println(( mulAns andThen isEvenAns)(5))
    }
}

Producción :

true
false

Explicación:

La primera salida es true ya que 4 se multiplica por 5, lo que da 20. Este 20 se pasa como parámetro a la función isEven.

La segunda salida es false, ya que primero se multiplica 5 por 5 y luego se comprueba su resultado en la función isEven.

Transforme funciones puras en funtores en Scala

Funtor se refiere al mapeo entre categorías, algo así como una función de entidades u objetos. Por ejemplo, tenemos las categorías A y B y un funtor F que mapea los objetos de A a los objetos de B.

trait Functor[F[_]] {
    def mapping[A, B](X: F[A])(f: A => B): F[B]

    def lifting[A, B](f: A => B): F[A] => F[B] =
        X => map(X)(f)
}

En este contexto, levantar se refiere a tomar una función de A=>B y transformarla en un funtor haciéndola una función de la forma F[A] => F[B]. Cuando se trabaja con tipos de datos anidados, esto puede ser muy útil.

Transformar funciones parciales a funciones en Scala

En este contexto, el levantamiento se refiere a la extensión del dominio. Las funciones parciales son tipos de funciones que se pueden aplicar a los subdominios de valores.

Pero a veces, es posible que queramos ampliar su dominio, y el levantamiento nos ayuda a lograrlo.

Supongamos que tenemos una función parcial que da la raíz cuadrada de un número positivo.

val sqrt: PartialFunction[Double, Double] =
{
    case temp if temp >= 0 => Math.sqrt(temp)
}

Ahora, podemos extender el dominio de nuestra función parcial utilizando el método lift para que se vea más elegante:

def getSqrtRootPartialFunction(t: Double) =
{
    sqrt.lift(t).map(ans => s"Square root of ${t} is ${ans}")
        .getOrElse(s"Cannot calculate square root for t")
}

Código de trabajo completo:

object MyClass {
     val sqrt: PartialFunction[Double, Double] = {
        case temp if temp >= 0 => Math.sqrt(temp)
    }

    def getSqrtRootPartialFunction(t: Double) = {
        sqrt.lift(t).map(ans => println(s"Square root of ${t} is ${ans}"))
           .getOrElse(println(s"Cannot calculate square root for t"))
    }

    def main(args: Array[String])
    {
        getSqrtRootPartialFunction(35)
    }
}

Producción :

Square root of 35.0 is 5.916079783099616

Explicación:

Entonces, lo que ha hecho el levantamiento de la función sqrt aquí es que extendió el dominio a un doble completo de PartialFunction[Double, Double] a una Function[Double, Option[Double]].

A veces, el levantamiento de funciones parciales se usa para evitar la excepción de índice fuera de límite.

Seq("1", "2", "3").lift(1) // Some("2")

Seq("1", "2", "3").lift(7) // none returned

El dominio se ha ampliado de String a Option[String]. Entonces, cuando tratamos de acceder a un valor fuera de límite, el Seq levantado devuelve None en lugar de lanzar una excepción out of bound.

Transformadores de mónadas en Scala

La combinación de mónadas se realiza mediante transformadores de mónadas. Digamos que tenemos dos Futures:

val helloWorld: Future[Option[String]] = Future.successful(Some("hello world"))
val language: Future[String] = Future.successful("this is Scala language")

Ahora, como ambos Futures tienen diferentes dominios, podemos usar transformadores de mónadas elevando language a OptionT. Por esto, podemos manejar el resultado de una manera más consistente:

def MonadTransformer() = {
    val message: OptionT[Future, String] = for {
        hello <- OptionT(helloWorld)
        name  <- OptionT.liftF(language)
    } yield println(s"$hello $name")

    val result: Future[Option[String]] = message.value

    Await.result(result, 1 second)
}

Conclusión

En este artículo, hemos aprendido el concepto de levantamiento y lo que significa en diferentes contextos. Es muy útil escribir nuestro código de una manera más componible e idiomática, lo que nos permite centrarnos más en la lógica comercial del código en lugar de perder el tiempo construyendo diferentes partes de él.

Autor: Suraj P
Suraj P avatar Suraj P avatar

A technophile and a Big Data developer by passion. Loves developing advance C++ and Java applications in free time works as SME at Chegg where I help students with there doubts and assignments in the field of Computer Science.

LinkedIn GitHub

Artículo relacionado - Scala Function