Exit e-book
Show all chapters
03
Una función pura debe ser determinística y debe depender sólo de sus entradas
03. 
Una función pura debe ser determinística y debe depender sólo de sus entradas

Sign up to our Newsletter

Signing up to our newsletter allows you to read all our ebooks.

    Introducción a la Programación con Efectos Funcionales usando ZIO
    03

    Una función pura debe ser determinística y debe depender sólo de sus entradas

    La segunda característica de una función es que debe ser determinística y debe depender sólo de sus entradas. Esto significa que para cada entrada que se provea a la función siempre se debe obtener la misma salida, sin importar cuántas veces la función sea llamada. Por ejemplo, la siguiente función para generar enteros aleatorios no es determinística:

    
    def generateRandomInt(): Int = (new scala.util.Random).nextInt
    

    Para demostrar por qué esta función no es determinística,  consideremos qué pasa la primera vez que llamamos a la función:

    
    generateRandomInt() // Resultado: -272770531
    

    Y luego, qué pasa si llamamos otra vez a la función:

    
    generateRandomInt() // Resultado: 217937820
    
    

    ¡Obtenemos resultados diferentes! Claramente esta función no es determinística, y su encabezado es engañoso otra vez, porque sugiere que no depende de ninguna entrada para producir una salida, cuando en realidad hay una dependencia escondida hacia un objeto scala.util.Random. Esto podría causar problemas, porque nunca podemos estar realmente seguros de cómo la función generateRandomInt se va a comportar, haciéndola difícil de testear.

    Ahora, veamos una definición alternativa. Para ello, usaremos un generador de números aleatorios personalizado, basado en un ejemplo presentado en el libro Functional Programming in Scala:

     

    
    final case class RNG(seed: Long) {
      def nextInt: (Int, RNG) = {
        val newSeed = (seed * 0x5DEECE66DL + 0xBL) & 0xFFFFFFFFFFFFL
        val nextRNG = RNG(newSeed)
        val n       = (newSeed >>> 16).toInt
        (n, nextRNG)
      }
    }
    
    def generateRandomInt(random: RNG): (Int, RNG) = random.nextInt
    
    
    

    Esta nueva versión de la función generateRandomInt es determinística: no importa cuántas veces se la llame, siempre obtendremos la misma salida para las misma entrada y el encabezado ahora muestra claramente la dependencia hacia la variable random. Por ejemplo:

    
    val random        = RNG(10)
    val (n1, random1) = generateRandomInt(random) // n1 = 3847489, random1 = RNG(252149039181)
    val (n2, random2) = generateRandomInt(random) // n2 = 3847489, random2 = RNG(252149039181)
    
    

    Si queremos generar un nuevo entero, debemos proveer una entrada distinta:

    
    val (n3, random3) = generateRandomInt(random2) // n3 = 1334288366, random3 = RNG(87443922374356)
    
    
    PREVIOUS
    Chapter
    02
    NEXT
    Chapter
    04