En la teoría del lenguaje de programación , la evaluación perezosa , o llamada por necesidad , [1] es una estrategia de evaluación que retrasa la evaluación de una expresión hasta que se necesita su valor ( evaluación no estricta ) y que también evita evaluaciones repetidas ( compartir ). [2] [3] El uso compartido puede reducir el tiempo de ejecución de ciertas funciones en un factor exponencial sobre otras estrategias de evaluación no estrictas, como la llamada por nombre , que evalúa repetidamente la misma función, a ciegas, independientemente de si la función puede ser memorizado .
Sin embargo, para operaciones prolongadas, sería más apropiado realizar antes de cualquier operación urgente, como manejar las entradas del usuario en un videojuego .
Los beneficios de la evaluación perezosa incluyen:
- La capacidad de definir el flujo de control (estructuras) como abstracciones en lugar de primitivas.
- La capacidad de definir estructuras de datos potencialmente infinitas . Esto permite una implementación más sencilla de algunos algoritmos.
- El rendimiento aumenta al evitar cálculos innecesarios y evitar condiciones de error al evaluar expresiones compuestas.
La evaluación perezosa se combina a menudo con memoization , como se describe en Jon Bentley 's programas eficientes de escritura . [4] Después de que se calcula el valor de una función para ese parámetro o conjunto de parámetros, el resultado se almacena en una tabla de búsqueda que está indexada por los valores de esos parámetros; la próxima vez que se llama a la función, se consulta la tabla para determinar si el resultado de esa combinación de valores de parámetro ya está disponible. Si es así, el resultado almacenado simplemente se devuelve. De lo contrario, la función se evalúa y se agrega otra entrada a la tabla de búsqueda para su reutilización.
La evaluación perezosa puede conducir a una reducción en la huella de memoria, ya que los valores se crean cuando es necesario. [5] Sin embargo, la evaluación perezosa es difícil de combinar con características imperativas como el manejo de excepciones y la entrada / salida , porque el orden de las operaciones se vuelve indeterminado. La evaluación perezosa puede introducir pérdidas de memoria . [6] [7]
Lo opuesto a la evaluación perezosa es la evaluación ansiosa , a veces conocida como evaluación estricta. La evaluación ávida es la estrategia de evaluación empleada en la mayoría de los lenguajes de programación [ cuantificar ] .
Historia
La evaluación perezosa fue introducida para el cálculo lambda por Christopher Wadsworth [8] y empleada por Plessey System 250 como una parte crítica de una metamáquina Lambda-Calculus, reduciendo la sobrecarga de resolución para el acceso a objetos en un espacio de direcciones de capacidad limitada. [9] Para los lenguajes de programación, fue introducido de forma independiente por Peter Henderson y James H. Morris [10] y por Daniel P. Friedman y David S. Wise. [11] [12]
Aplicaciones
La evaluación retrasada se usa particularmente en lenguajes de programación funcionales . Cuando se usa la evaluación retrasada, una expresión no se evalúa tan pronto como se vincula a una variable, sino cuando el evaluador se ve obligado a producir el valor de la expresión. Es decir, una declaración como x = expression;
(es decir, la asignación del resultado de una expresión a una variable) claramente exige que se evalúe la expresión y se coloque el resultado x
, pero lo que realmente está incluido x
es irrelevante hasta que se necesite su valor. a través de una referencia x
en alguna expresión posterior cuya evaluación podría aplazarse, aunque eventualmente el árbol de dependencias de rápido crecimiento se podaría para producir algún símbolo en lugar de otro para que el mundo exterior lo viera. [13]
La evaluación retrasada tiene la ventaja de poder crear listas infinitas calculables sin bucles infinitos o cuestiones de tamaño que interfieran en el cálculo. Por ejemplo, se podría crear una función que cree una lista infinita (a menudo llamada flujo ) de números de Fibonacci . El cálculo del n -ésimo número de Fibonacci sería simplemente la extracción de ese elemento de la lista infinita, lo que obligaría a evaluar solo los primeros n miembros de la lista. [14] [15]
Por ejemplo, en el lenguaje de programación Haskell , la lista de todos los números de Fibonacci se puede escribir como: [15]
fibs = 0 : 1 : zipWith ( + ) fibs ( tail fibs )
En la sintaxis de Haskell, " :
" antepone un elemento a una lista, tail
devuelve una lista sin su primer elemento y zipWith
usa una función específica (en este caso, la adición) para combinar los elementos correspondientes de dos listas para producir una tercera. [14]
Siempre que el programador sea cuidadoso, solo se evalúan los valores que se requieren para producir un resultado en particular. Sin embargo, ciertos cálculos pueden hacer que el programa intente evaluar un número infinito de elementos; por ejemplo, solicitar la longitud de la lista o intentar sumar los elementos de la lista con una operación de plegado daría como resultado que el programa no terminara o se quedara sin memoria .
Estructuras de Control
En casi todos [ cuantifique ] los lenguajes "ansiosos" comunes, si las declaraciones se evalúan de manera perezosa.
si a entonces b si no c
evalúa (a), entonces si y solo si (a) se evalúa como verdadero, evalúa (b), de lo contrario evalúa (c). Es decir, no se evaluarán ni (b) ni (c). Por el contrario, en un lenguaje ansioso, el comportamiento esperado es que
definir f (x, y) = 2 * xestablecer k = f (d, e)
seguirá evaluando (e) al calcular el valor de f (d, e) aunque (e) no se utilice en la función f. Sin embargo, las estructuras de control definidas por el usuario dependen de la sintaxis exacta, por ejemplo
definir g (a, b, c) = si a entonces b si no cl = g (h, i, j)
(i) y (j) se evaluarían en un lenguaje ávido. Mientras que en un idioma perezoso,
l '= si h entonces yo si no j
Se evaluarían (i) o (j), pero nunca ambos.
La evaluación diferida permite que las estructuras de control se definan normalmente y no como primitivas o técnicas en tiempo de compilación. Si (i) o (j) tienen efectos secundarios o introducen errores de tiempo de ejecución, las diferencias sutiles entre (l) y (l ') pueden ser complejas. Por lo general, es posible introducir estructuras de control perezosas definidas por el usuario en lenguajes ansiosos como funciones, aunque pueden apartarse de la sintaxis del lenguaje para una evaluación ansiosa: a menudo, los cuerpos de código involucrados (como (i) y (j)) deben estar envueltos en un valor de función, de modo que se ejecuten solo cuando se llaman.
La evaluación de cortocircuito de las estructuras de control booleanas a veces se denomina perezosa .
Trabajar con estructuras de datos infinitas
Muchos lenguajes ofrecen la noción de estructuras de datos infinitas . Estos permiten que las definiciones de los datos se den en términos de rangos infinitos o recursividad sin fin, pero los valores reales solo se calculan cuando es necesario. Tomemos, por ejemplo, este programa trivial en Haskell:
numberFromInfiniteList :: Int -> Int numberFromInfiniteList n = infinito !! n - 1 donde infinito = [ 1 .. ]main = imprimir $ numberFromInfiniteList 4
En la función numberFromInfiniteList , el valor de infinito es un rango infinito, pero hasta que se necesite un valor real (o más específicamente, un valor específico en un índice determinado), la lista no se evalúa, e incluso entonces solo se evalúa según sea necesario (es decir, hasta que el índice deseado .)
Patrón de lista de éxitos
Evitando un esfuerzo excesivo
Una expresión compuesta puede tener el formato EasilyComputed o LotsOfWork, de modo que si la parte fácil da verdadero, se podría evitar una gran cantidad de trabajo. Por ejemplo, suponga que se debe verificar un gran número N para determinar si es un número primo y una función IsPrime (N) está disponible, pero lamentablemente, puede requerir muchos cálculos para evaluar. Quizás N = 2 o [Mod (N, 2) ≠ 0 e IsPrime (N)] ayudarán si va a haber muchas evaluaciones con valores arbitrarios para N.
Evitación de condiciones de error
Una expresión compuesta puede tener el formato SafeTo Try y Expression, por lo que si SafeTo Try es falso, no se debe intentar evaluar la expresión para que no se señale un error en tiempo de ejecución, como dividir por cero o indexar fuera de los límites, etc. Por ejemplo, el siguiente pseudocódigo ubica el último elemento distinto de cero de una matriz:
L: = Longitud (A); Mientras que L> 0 y A (L) = 0 hacen L: = L - 1;
Si todos los elementos de la matriz son cero, el ciclo funcionará hasta L = 0 y, en este caso, el ciclo debe terminarse sin intentar hacer referencia al elemento cero de la matriz, que no existe.
Otros usos
En los sistemas de ventanas de computadora , la pintura de información en la pantalla es impulsada por eventos de exposición que impulsan el código de pantalla en el último momento posible. Al hacer esto, los sistemas de ventanas evitan el cálculo de actualizaciones de contenido de pantalla innecesarias. [dieciséis]
Otro ejemplo de pereza en los sistemas informáticos modernos es la asignación de páginas de copia en escritura o la paginación por demanda , donde la memoria se asigna solo cuando se cambia un valor almacenado en esa memoria. [dieciséis]
La pereza puede ser útil para escenarios de alto rendimiento. Un ejemplo es la función mmap de Unix , que proporciona la carga de páginas desde el disco impulsada por la demanda , de modo que solo las páginas realmente tocadas se cargan en la memoria y no se asigna la memoria innecesaria.
MATLAB implementa copiar al editar , donde las matrices que se copian tienen su almacenamiento de memoria real replicado solo cuando se cambia su contenido, lo que posiblemente conduce a un error de memoria insuficiente al actualizar un elemento posteriormente en lugar de durante la operación de copia. [17]
Implementación
Algunos lenguajes de programación retrasan la evaluación de expresiones de forma predeterminada, y otros proporcionan funciones o sintaxis especial para retrasar la evaluación. En Miranda y Haskell , la evaluación de los argumentos de función se retrasa de forma predeterminada. En muchos otros idiomas, la evaluación puede ser retrasado mediante la suspensión de forma explícita el cálculo utilizando la sintaxis especial (como ocurre con el esquema de " delay
" y " force
" y OCaml 's ' lazy
' y " Lazy.force
") o, más generalmente, envolviendo la expresión en un golpe seco . El objeto que representa una evaluación tan explícitamente retrasada se llama futuro perezoso . Raku usa la evaluación perezosa de listas, por lo que uno puede asignar listas infinitas a variables y usarlas como argumentos para funciones, pero a diferencia de Haskell y Miranda, Raku no usa la evaluación perezosa de operadores aritméticos y funciones por defecto. [13]
Pereza y afán
Controlar el entusiasmo en lenguajes perezosos
En los lenguajes de programación perezosos como Haskell, aunque el valor predeterminado es evaluar las expresiones sólo cuando se exigen, en algunos casos es posible hacer que el código sea más ansioso o, por el contrario, hacerlo más perezoso nuevamente después de que se haya hecho más ansioso. Esto se puede hacer codificando explícitamente algo que fuerce la evaluación (lo que puede hacer que el código sea más ansioso) o evitando dicho código (lo que puede hacer que el código sea más perezoso). La evaluación estricta suele implicar entusiasmo, pero son conceptos técnicamente diferentes.
Sin embargo, hay una optimización implementada en algunos compiladores llamada análisis de rigurosidad , que, en algunos casos, permite al compilador inferir que siempre se usará un valor. En tales casos, esto puede hacer que la elección del programador de forzar o no ese valor en particular sea irrelevante, porque el análisis de rigor forzará una evaluación estricta.
En Haskell, marcar los campos del constructor como estrictos significa que sus valores siempre se exigirán de inmediato. La seq
función también se puede usar para exigir un valor inmediatamente y luego pasarlo, lo cual es útil si un campo de constructor generalmente debe ser perezoso. Sin embargo, ninguna de estas técnicas implementa un rigor recursivo ; para eso, deepSeq
se inventó una función llamada .
Además, la coincidencia de patrones en Haskell 98 es estricta de forma predeterminada, por lo que el ~
calificador debe usarse para hacerlo perezoso. [18]
Simular la pereza en idiomas ávidos
Java
En Java , la evaluación diferida se puede realizar mediante el uso de objetos que tienen un método para evaluarlos cuando se necesita el valor. El cuerpo de este método debe contener el código necesario para realizar esta evaluación. Desde la introducción de expresiones lambda en Java SE8, Java ha admitido una notación compacta para esto. El siguiente ejemplo de interfaz genérica proporciona un marco para la evaluación diferida: [19] [20]
interfaz Lazy < T > { T eval (); }
La Lazy
interfaz con su eval()
método es equivalente a la Supplier
interfaz con su get()
método en la java.util.function
biblioteca. [21]
Cada clase que implementa la Lazy
interfaz debe proporcionar un eval
método, y las instancias de la clase pueden tener los valores que el método necesite para realizar una evaluación perezosa. Por ejemplo, considere el siguiente código para calcular e imprimir perezosamente 2 10 :
Perezoso < Entero > a = () -> 1 ; for ( int i = 1 ; i <= 10 ; i ++ ) { final Lazy < Integer > b = a ; a = () -> b . eval () + b . eval (); } Sistema . fuera . println ( "a =" + a . eval () );
En lo anterior, la variable a inicialmente se refiere a un objeto entero diferido creado por la expresión lambda ()->1
. Evaluar esta expresión lambda equivale a construir una nueva instancia de una clase anónima que se implementa Lazy
con una método eval que regresa 1 .
Cada iteración de los enlaces de bucle a a un nuevo objeto creado mediante la evaluación de la expresión lambda dentro del bucle. Cada uno de estos objetos tiene una referencia a otro objeto perezoso, b , y tiene un eval método que llama b.eval()
dos veces y devuelve la suma. La variable b es necesario aquí para cumplir con el requisito de Java de que las variables a las que se hace referencia desde dentro de una expresión lambda sean finales.
Este es un programa ineficiente porque esta implementación de enteros perezosos no memoriza el resultado de llamadas anteriores a eval . También implica una considerable cantidad de autoboxing y unboxing . Lo que puede no ser obvio es que, al final del ciclo, el programa ha construido una lista enlazada de 11 objetos y que todas las adiciones reales involucradas en el cálculo del resultado se realizan en respuesta a la llamada a a.eval()
en la línea final de código. Esta llamada recorre recursivamente la lista para realizar las adiciones necesarias.
Podemos construir una clase Java que memorice objetos perezosos de la siguiente manera: [19] [20]
class Memo < T > implementa Lazy < T > { privado Lazy < T > lazy ; // una expresión perezosa, eval la establece en nulo private T memo = null ; // el memorando del valor anterior public Memo ( Lazy < T > lazy ) { // constructor this . perezoso = perezoso ; } public T eval () { if ( lazy ! = null ) { memo = lazy . eval (); perezoso = nulo ; } nota de devolución ; } }
Esto permite reescribir el ejemplo anterior para que sea mucho más eficiente. Donde el original se ejecutó en tiempo exponencial en el número de iteraciones, la versión memorizada se ejecuta en tiempo lineal:
Perezoso < Entero > a = () -> 1 ; for ( int i = 1 ; i <= 10 ; i ++ ) { final Lazy < Integer > b = a ; a = nuevo Memo < Entero > ( () -> b . eval () + b . eval () ); } Sistema . fuera . println ( "a =" + a . eval () );
Tenga en cuenta que las expresiones lambda de Java son simplemente azúcar sintáctico . Todo lo que pueda escribir con una expresión lambda se puede reescribir como una llamada para construir una instancia de una clase interna anónima que implemente la interfaz, y cualquier uso de una clase interna anónima se puede reescribir usando una clase interna con nombre, y cualquier clase interna con nombre puede ser movido al nivel de anidación más externo.
JavaScript
En JavaScript , la evaluación diferida se puede simular utilizando un generador . Por ejemplo, el flujo de todos los números de Fibonacci se puede escribir, usando memorización , como:
/ ** * Las funciones generadoras devuelven objetos generadores, que reifican la evaluación perezosa. * @return {! Generator } Un generador de enteros no nulo. * / function * fibonacciNumbers () { dejar memo = [ 1n , - 1n ]; // crea el estado inicial (por ejemplo, un vector de números "negafibonacci") while ( verdadero ) { // repite indefinidamente memo = [ memo [ 0 ] + memo [ 1 ], memo [ 0 ]]; // actualiza el estado de cada nota de rendimiento de evaluación [ 0 ]; // producir el siguiente valor y suspender la ejecución hasta que se reanude } } let stream = fibonacciNumbers (); // crea un flujo de números evaluados de forma perezosa let first10 = Array . from ( new Array ( 10 ), () => stream . next (). value ); // evalúa solo los primeros 10 números de la consola . log ( primeros 10 ); // la salida es [0n, 1n, 1n, 2n, 3n, 5n, 8n, 13n, 21n, 34n]
Pitón
En Python 2.x, la range()
función [22] calcula una lista de enteros. La lista completa se almacena en la memoria cuando se evalúa la primera declaración de asignación, por lo que este es un ejemplo de evaluación ansiosa o inmediata:
>>> r = rango ( 10 ) >>> imprimir r [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> imprimir r [ 3 ] 3
En Python 3.x, la range()
función [23] devuelve un objeto de rango especial que calcula elementos de la lista bajo demanda. Los elementos del objeto de rango solo se generan cuando se necesitan (por ejemplo, cuando print(r[3])
se evalúa en el siguiente ejemplo), por lo que este es un ejemplo de evaluación diferida o diferida:
>>> r = rango ( 10 ) >>> imprimir ( r ) rango (0, 10) >>> imprimir ( r [ 3 ]) 3
- Este cambio a la evaluación diferida ahorra tiempo de ejecución para rangos grandes a los que nunca se puede hacer referencia por completo y el uso de memoria para rangos grandes donde solo se necesitan uno o unos pocos elementos en cualquier momento.
En Python 2.x es posible usar una función llamada xrange()
que devuelve un objeto que genera los números en el rango a pedido. La ventaja de xrange
es que el objeto generado siempre ocupará la misma cantidad de memoria.
>>> r = xrange ( 10 ) >>> print ( r ) xrange (10) >>> lst = [ x para x en r ] >>> print ( lst ) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Desde la versión 2.2 en adelante, Python manifiesta una evaluación perezosa mediante la implementación de iteradores (secuencias perezosas) a diferencia de las secuencias de tuplas o listas. Por ejemplo (Python 2):
>>> números = rango ( 10 ) >>> iterador = iter ( números ) >>> imprimir números [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> imprimir iterador < objeto listiterator en 0xf7e8dd4c> >>> iterador de impresión . siguiente () 0
- El ejemplo anterior muestra que las listas se evalúan cuando se llaman, pero en el caso del iterador, el primer elemento '0' se imprime cuando surge la necesidad.
.NET Framework
En .NET Framework es posible realizar una evaluación diferida usando la clase . [24] La clase se puede explotar fácilmente en F # usando la palabra clave, mientras que el método forzará la evaluación. También hay colecciones especializadas como las que brindan soporte integrado para la evaluación diferida.System.Lazy<T>
lazy
force
Microsoft.FSharp.Collections.Seq
sea fibonacci = Seq . desplegar ( diversión ( x , y ) -> Algunos ( x , ( y , x + y ))) ( 0I , 1I ) fibonacci |> Seq . nth 1000
En C # y VB.NET, la clase se usa directamente.System.Lazy<T>
public int Sum () { int a = 0 ; int b = 0 ; Lazy < int > x = new Lazy < int > (() => a + b ); a = 3 ; b = 5 ; devuelve x . Valor ; // devuelve 8 }
O con un ejemplo más práctico:
// cálculo recursivo del n-ésimo número de fibonacci public int Fib ( int n ) { return ( n == 1 )? 1 : ( n == 2 )? 1 : Fib ( n - 1 ) + Fib ( n - 2 ); }public void Main () { Console . WriteLine ( "¿Qué número de Fibonacci desea calcular?" ); int n = Int32 . Analizar ( Consola . ReadLine ()); Lazy < int > fib = new Lazy < int > (() => Fib ( n )); // la función está preparada, pero no se ejecuta bool execute ; si ( n > 100 ) { Consola . WriteLine ( "Esto puede llevar algo de tiempo. ¿Realmente desea calcular este gran número? [S / n]" ); ejecutar = ( Consola . ReadLine () == "y" ); } más ejecutar = verdadero ; si ( ejecutar ) Console . WriteLine ( FIB . Valor ); // el número solo se calcula si es necesario }
Otra forma es usar la yield
palabra clave:
// evaluación ansiosa pública IEnumerable < int > Fibonacci ( int x ) { IList < int > fibs = new List < int > (); int prev = - 1 ; int siguiente = 1 ; para ( int i = 0 ; i < x ; i ++) { int suma = anterior + siguiente ; prev = siguiente ; siguiente = suma ; mentiras . Suma ( suma ); } return fibs ; }// evaluación diferida public IEnumerable < int > LazyFibonacci ( int x ) { int prev = - 1 ; int siguiente = 1 ; para ( int i = 0 ; i < x ; i ++) { int suma = anterior + siguiente ; prev = siguiente ; siguiente = suma ; rendimiento de la suma de retorno ; } }
Ver también
- Lógica combinatoria
- Zurra
- Flujo de datos
- Evaluación entusiasta
- Programación funcional
- Futuros y promesas
- Generador (programación de computadoras)
- Reducción de gráfico
- Computación incremental : un concepto relacionado mediante el cual los cálculos solo se repiten si cambian sus entradas. Puede combinarse con una evaluación perezosa.
- Cálculo lambda
- Inicialización perezosa
- Mirar hacia el futuro
- Lenguaje de programación no estricto
- Evaluación normal de pedidos
- Evaluación de cortocircuito (mínimo)
Referencias
- ^ Hudak , 1989 , p. 384
- ^ David Anthony Watt; William Findlay (2004). Conceptos de diseño de lenguajes de programación . John Wiley e hijos. págs. 367–368. ISBN 978-0-470-85320-7. Consultado el 30 de diciembre de 2010 .
- ^ Reynolds 1998 , p. 307
- ^ Bentley, Jon Louis. Redacción de programas eficientes. Prentice-Hall, 1985. ISBN 978-0139702440
- ^ Chris Smith (22 de octubre de 2009). Programando F # . O'Reilly Media, Inc. pág. 79. ISBN 978-0-596-15364-9. Consultado el 31 de diciembre de 2010 .
- ^ Launchbury 1993 .
- ^ Edward Z. Yang. "Zoológico de fuga espacial" .
- ^ Wadsworth, 1971
- ^ Hamer-Hodges, Kenneth (1 de enero de 2020). Civilizando el ciberespacio: la lucha por la democracia digital . pag. 410. ISBN 978-1-95-163044-7. Consultado el 29 de febrero de 2020 .
- ^ Henderson y Morris 1976
- ^ Friedman y Wise, 1976
- ^ Reynolds 1998 , p. 312
- ^ a b Philip Wadler (2006). Programación funcional y lógica: 8º simposio internacional, FLOPS 2006, Fuji-Susono, Japón, 24-26 de abril de 2006: actas . Saltador. pag. 149. ISBN 978-3-540-33438-5. Consultado el 14 de enero de 2011 .
- ^ a b Daniel Le Métayer (2002). Lenguajes y sistemas de programación: 11º Simposio Europeo de Programación, ESOP 2002, celebrado como parte de las Conferencias Europeas Conjuntas sobre Teoría y Práctica del Software, ETAPS 2002, Grenoble, Francia, 8-12 de abril de 2002: actas . Saltador. págs. 129-132. ISBN 978-3-540-43363-7. Consultado el 14 de enero de 2011 .
- ^ a b Asociación para Maquinaria de Computación; Grupo de interés especial de la ACM sobre lenguajes de programación (1 de enero de 2002). Actas del taller ACM SIGPLAN Haskell de 2002 (Haskell '02): Pittsburgh, Pennsylvania, EE. UU.; 3 de octubre de 2002 . Asociación para Maquinaria de Computación. pag. 40. ISBN 978-1-58113-605-0. Consultado el 14 de enero de 2011 .
- ^ a b Mayordomo de ejecución perezoso y especulativo Lampson Microsoft Research OPODIS, Burdeos, Francia 12 de diciembre de 2006
- ^ "¿Sin memoria al asignar valores a matrices existentes? - MATLAB Answers - MATLAB Central" .
- ^ "Coincidencia de patrón perezoso - HaskellWiki" .
- ^ a b Grzegorz Piwowarek, Aprovechando las expresiones Lambda para la evaluación perezosa en Java , 4Comprehension , 25 de julio de 2018.
- ^ a b Douglas W.Jones, CS: 2820 Notes, otoño de 2020, conferencia 25 , consultado en enero de 2021.
- ^ Interface Suppier , consultado en octubre de 2020.
- ^ "2. Funciones integradas - Documentación de Python 2.7.11" .
- ^ "2. Funciones integradas - Documentación de Python 3.5.1" .
- ^ "Lazy (T) Class (System)" . Microsoft.
Otras lecturas
- Hudak, Paul (septiembre de 1989). "Concepción, evolución y aplicación de lenguajes de programación funcional". Encuestas de computación ACM . 21 (3): 383–385. doi : 10.1145 / 72551.72554 .
- Reynolds, John C. (1998). Teorías de lenguajes de programación . Prensa de la Universidad de Cambridge . ISBN 9780521594141. Consultado el 23 de febrero de 2016 .
- Henderson, Peter ; Morris, James H. (enero de 1976). "Un evaluador perezoso" . Acta de la conferencia del Tercer Simposio ACM sobre Principios de Lenguajes de Programación .
- Friedman, DP ; Wise, David S. (1976). S. Michaelson; R. Milner (eds.). "Los contras no deben evaluar sus argumentos" (PDF) . Tercer Coloquio Internacional Autómatas de Lenguajes y Programación . Prensa de la Universidad de Edimburgo.
- Launchbury, John (1993). "Una semántica natural para la evaluación perezosa". Actas del 20º Simposio ACM SIGPLAN-SIGACT sobre principios de lenguajes de programación (POPL '93) : 144–154. CiteSeerX 10.1.1.35.2016 . doi : 10.1145 / 158511.158618 . ISBN 0897915607.
enlaces externos
- Macros de evaluación diferida en Nemerle
- Cálculo lambda en bibliotecas Boost en C ++ lenguaje
- Lazy Evaluation en ANSI C ++ escribiendo código en un estilo que usa clases para implementar cierres de funciones .