Saltar al contenido

¿Qué significa el signo de exclamación en una declaración de Haskell?

Después de observar en diversos repositorios y sitios webs al final dimos con la resolución que te compartiremos ahora.

Solución:

Es una declaración de rigor. Básicamente, significa que debe evaluarse en lo que se denomina “forma normal de cabeza débil” cuando se crea el valor de la estructura de datos. Veamos un ejemplo, para que podamos ver lo que esto significa:

data Foo = Foo Int Int !Int !(Maybe Int)

f = Foo (2+2) (3+3) (4+4) (Just (5+5))

La función f arriba, cuando se evalúe, devolverá un “thunk”: es decir, el código a ejecutar para averiguar su valor. En ese momento, un Foo ni siquiera existe todavía, solo el código.

Pero en algún momento alguien puede intentar mirar dentro, probablemente a través de una coincidencia de patrón:

case f of
     Foo 0 _ _ _ -> "first arg is zero"
     _           -> "first arge is something else"

Esto ejecutará suficiente código para hacer lo que necesita, y nada más. Entonces creará un Foo con cuatro parámetros (porque no puedes mirar dentro sin que exista). El primero, ya que lo estamos probando, necesitamos evaluar todo el camino para 4donde nos damos cuenta de que no coincide.

El segundo no necesita ser evaluado, porque no lo estamos probando. Así, más que 6 almacenado en esa ubicación de memoria, solo almacenaremos el código para una posible evaluación posterior, (3+3). Eso se convertirá en un 6 solo si alguien lo mira.

El tercer parámetro, sin embargo, tiene un ! delante de él, por lo que se evalúa estrictamente: (4+4) se ejecuta, y 8 se almacena en esa ubicación de memoria.

El cuarto parámetro también se evalúa estrictamente. Pero aquí es donde se pone un poco complicado: no estamos evaluando completamente, sino solo una forma de cabeza normal débil. Esto significa que averiguamos si es Nothing o Just algo, y almacenar eso, pero no vamos más lejos. Eso significa que no almacenamos Just 10 pero en realidad Just (5+5), dejando el thunk dentro sin evaluar. Es importante saber esto, aunque creo que todas las implicaciones de esto van más allá del alcance de esta pregunta.

Puede anotar los argumentos de la función de la misma manera, si habilita el BangPatterns extensión de idioma:

f x !y = x*y

f (1+1) (2+2) devolverá el thunk (1+1)*4.

Una forma sencilla de ver la diferencia entre argumentos de constructores estrictos y no estrictos es cómo se comportan cuando no están definidos. Dado

data Foo = Foo Int !Int

first (Foo x _) = x
second (Foo _ y) = y

Dado que el argumento no estricto no es evaluado por secondpasando en undefined no causa un problema:

> second (Foo undefined 1)
1

Pero el argumento estricto no puede ser undefinedincluso si no usamos el valor:

> first (Foo 1 undefined)
*** Exception: Prelude.undefined

Creo que es una anotación estricta.

Haskell es un puro y perezoso lenguaje funcional, pero a veces la sobrecarga de la pereza puede ser demasiado o un desperdicio. Entonces, para lidiar con eso, puede pedirle al compilador que evalúe completamente los argumentos de una función en lugar de analizar los procesadores.

Hay más información en esta página: Rendimiento/Estrictez.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *