Haskell Hero

Haskell Hero es un manual interactivo del lenguaje Haskell para principiantes.

Evaluación II

Desde las instrucciones hasta el resultado

Ejemplo

Evaluad paso a paso la expresión tresVeces (5 + 2) donde

tresVeces x = x + x + x


¿Cómo empezar? ¿Evaluar primero 5 + 2 o aplicar primero la definición de la función tresVeces?

La respuesta es: Depende de la estrategia de evaluación elegida.

  • la estrategia de evaluación normal
  • la estrategia de evaluación estricta
  • la estrategia de evaluación perezosa

Sin definirlo explícitamente de otra manera, Haskell evalúa de manera perezosa.

Evaluación normal

La estrategia de evaluación normal significa la evaluación de afuera hacia adentro (en otras palabras, la evaluación mediante paso por nombre). En concreto, si la expresión está en forma f x y f se puede aplicar a x, aplicamos f a x. En caso contrario, evaluamos f mismo, otra vez según la estrategia de evaluación normal.

En breve: Sin mirar a la evaluación de parámetros aplicamos la función f.

La expresión de ejemplo se evaluaría según la estrategia de evaluación normal de manera siguiente:

tresVeces (5 + 2)

~>  (5 + 2) + (5 + 2) + (5 + 2)
~>     7    + (5 + 2) + (5 + 2)
~>     7    +    7    + (5 + 2)
~>     7    +    7    +    7
~>          14        +    7
~>  21

Evaluación esctricta

La estrategia de evaluación estricta significa la evaluación de adentro hacia afuera (en otras palabras, la evaluación mediante paso por valor). En conreto, primero evaluamos parámetros a expresiones irreducibles y solo después aplicamos la función.

La expresión de ejemplo se evaluaría según la estrategia de evaluación estricta de manera siguiente:

tresVeces (5 + 2)

~>  tresVeces 7
~>  7 + 7 + 7
~>    14  + 7
~>  21

Evaluación perezosa

La estrageia de evaluación perezosa funciona casi de misma manera como la evaluación normal.Sin embargo, a diferencia de la evaluación normal, cuando evaluamos de manera perezosa, recordamos los resultados de evaluaciones de expresiones individuales. Antes de la evaluación primero miramos si ya no hemos evaluado tal expresión. Si es así, utilizamos el resultado de la evaluación anterior.

La expresión de ejemplo se evaluaría según la estrategia de evaluación perezosa de manera siguiente:

tresVeces (5 + 2)

~>  (5 + 2) + (5 + 2) + (5 + 2)
~>  7 + 7 + 7
~>    14  + 7
~>  21

¿Por qué estrategias diferentes?

Parece que la estrategia estricta es la más efectiva. No hay que controlar si la expresión ya se ha evaluado y es la estrategia más rápida. Entonces, ¿por qué necesitamos otras dos estrategias?

Por ejemplo evaluemos la expresión take 3 [1..]. La lista de primeros tres elementos de una lista infinita que empieza con uno es [1,2,3]. ¿Cómo se evaluaría según la estrategia estricta?

take 3 [1..]

~>  take 3 ( 1: [2..] )
~>  take 3 ( 1: 2: [3..] )
~>  take 3 ( 1: 2: 3: [4..] )
~>  take 3 ( 1: 2: 3: 4: [5..] )
~>  take 3 ( 1: 2: 3: 4: 5: [6..] )
~>  take 3 ( 1: 2: 3: 4: 5: 6: [7..] )
~>  ...

La evaluación no terminaría nunca porque la evaluación estricta requiere que se simplifiquen todos los parámetros, lo que no se puede hacer evaluando una lista infinita. Evaluando según la estrategia normal llegamos a esto:
take 3 [1..]

~>  take 3 ( 1: [2..] )

~>  1 : take 2 [2..]

~>  1 : take 2 ( 2: [3..] )

~>  1 : 2 : take 1 [3..]

~>  1 : 2 : take 1 ( 3: [4..] )

~>  1 : 2 : 3 : take 0 [4..]

~>  1 : 2 : 3 : []

Otro ejemplo podría ser la evaluación de expresiones con valores booleanos.
False && _  =  False
True  && x  =  x
------------------------

False && ( and [True, True..] )

~>  False

Si evaluáramos de manera estricta, la evaluación no terminaría nunca. Si evaluamos de manera normal/perezosa, llegamos hasta el resultado después de un paso.

Usamos la evaluación perezosa para prevenir la evaluación múltiple de las mismas expresiones.