Buscar..


Patrones de explosión

Los patrones anotados con una explosión ( ! ) Se evalúan estrictamente en lugar de perezosamente.

foo (!x, y) !z = [x, y, z] 

En este ejemplo, tanto x como z se evaluarán con una forma normal de encabezado débil antes de devolver la lista. Es equivalente a:

foo (x, y) z = x `seq` z `seq` [x, y, z]

Los patrones de Bang se habilitan utilizando la extensión de lenguaje BangPatterns Haskell 2010.

Formas normales

Este ejemplo proporciona una breve descripción general: para ver una explicación más detallada de formas y ejemplos normales , consulte esta pregunta .

Forma normal reducida

La forma normal reducida (o simplemente la forma normal, cuando el contexto es claro) de una expresión es el resultado de evaluar todas las subexpresiones reducibles en la expresión dada. Debido a la semántica no estricta de Haskell (normalmente llamada pereza ), una subexpresión no es reducible si está bajo un aglutinante (es decir, una abstracción lambda - \x -> .. ). La forma normal de una expresión tiene la propiedad de que, si existe, es única.

En otras palabras, no importa (en términos de semántica denotacional) en qué orden se reducen las subexpresiones. Sin embargo, la clave para escribir los programas de Haskell de rendimiento a menudo es garantizar que la expresión correcta se evalúe en el momento adecuado, es decir, la comprensión de la semántica operacional.

Una expresión cuya forma normal es en sí misma se dice que está en forma normal .

Algunas expresiones, por ejemplo, let x = 1:x in x , no tienen forma normal, pero siguen siendo productivas. La expresión de ejemplo todavía tiene un valor , si se admiten valores infinitos, que aquí está la lista [1,1, ...] . Otras expresiones, como let y = 1+y in y , no tienen ningún valor o su valor undefined está undefined .

Forma normal de la cabeza débil

El RNF corresponde a la evaluación completa de una expresión. Del mismo modo, la forma normal de la cabeza débil (WHNF, por sus siglas en inglés) corresponde a la evaluación del encabezado de la expresión. El encabezado de una expresión e se evalúa completamente si e es una aplicación Con e1 e2 .. en y Con es un constructor; o una abstracción \x -> e1 ; o una aplicación parcial f e1 e2 .. en , donde aplicación parcial significa f toma más de n argumentos (o, de manera equivalente, el tipo de e es un tipo de función). En cualquier caso, las subexpresiones e1..en pueden evaluarse o no evaluarse para que la expresión esté en WHNF, incluso pueden estar undefined .

La semántica de evaluación de Haskell se puede describir en términos de WHNF: para evaluar una expresión e , primero evalúela a WHNF, luego evalúe recursivamente todas sus subexpresiones de izquierda a derecha.

La primitiva seq función se utiliza para evaluar una expresión a WHNF. seq xy es denotacionalmente igual a y (el valor de seq xy es precisamente y ); además, x se evalúa como WHNF cuando y se evalúa como WHNF. Una expresión también se puede evaluar a WHNF con un patrón de bang (habilitado por la extensión -XBangPatterns ), cuya sintaxis es la siguiente:

f !x y = ... 

En que x se evaluará a WHNF cuando f se evalúa, mientras que y no se evalúa (necesariamente). Un patrón de explosión también puede aparecer en un constructor, por ejemplo,

data X = Con A !B C .. N

en cuyo caso se dice que el constructor Con es estricto en el campo B , lo que significa que el campo B se evalúa a WHNF cuando el constructor se aplica a argumentos suficientes (aquí, dos).

Patrones perezosos

Los patrones perezosos o irrefutables (indicados con syntax ~pat ) son patrones que siempre coinciden, sin siquiera mirar el valor coincidente. Esto significa que los patrones perezosos coincidirán incluso con los valores inferiores. Sin embargo, los usos subsiguientes de las variables vinculadas en sub-patrones de un patrón irrefutable forzarán la coincidencia del patrón a ocurrir, evaluándose al final a menos que la coincidencia sea exitosa.

La siguiente función es perezosa en su argumento:

f1 :: Either e Int -> Int
f1 ~(Right 1) = 42

y así conseguimos

λ» f1 (Right 1)
42
λ» f1 (Right 2)
42
λ» f1 (Left "foo")
42
λ» f1 (error "oops!")
42
λ» f1 "oops!"
*** type mismatch ***

La siguiente función está escrita con un patrón perezoso, pero de hecho está utilizando la variable del patrón que fuerza la coincidencia, por lo que fallará para los argumentos de la Left :

f2 :: Either e Int -> Int
f2 ~(Right x) = x + 1

λ» f2 (Right 1)
2
λ» f2 (Right 2)
3
λ» f2 (Right (error "oops!"))
*** Exception: oops!
λ» f2 (Left "foo")
*** Exception: lazypat.hs:5:1-21: Irrefutable pattern failed for pattern (Right x)
λ» f2 (error "oops!")
*** Exception: oops! 

let enlaces sean perezosos, se comportan como patrones irrefutables:

act1 :: IO ()
act1 = do
    ss <- readLn
    let [s1, s2] = ss :: [String]
    putStrLn "Done"

act2 :: IO ()
act2 = do
    ss <- readLn
    let [s1, s2] = ss
    putStrLn s1

Aquí act1 trabaja en entradas que se analizan en cualquier lista de cadenas, mientras que en act2 el putStrLn s1 necesita el valor de s1 que fuerza la coincidencia del patrón para [s1, s2] , así que solo funciona para listas de exactamente dos cadenas:

λ» act1
> ["foo"]
Done
λ» act2
> ["foo"]
*** readIO: no parse ***

Campos estrictos

En una declaración de data , el prefijo de un tipo con un bang ( ! ) Hace que el campo sea un campo estricto . Cuando se aplique el constructor de datos, esos campos se evaluarán con una forma normal de encabezado débil, por lo que se garantiza que los datos en los campos siempre estarán en forma normal de encabezado débil.

Los campos estrictos se pueden usar en los tipos de registro y no de registro:

data User = User
    { identifier :: !Int
    , firstName :: !Text
    , lastName :: !Text
    }

data T = MkT !Int !Int


Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow