Ricerca…


Bang Patterns

I pattern annotati con il botto ( ! ) Vengono valutati rigorosamente anziché pigramente.

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

In questo esempio, x e z verranno entrambi valutati in forma normale deboli prima di restituire l'elenco. È equivalente a:

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

I modelli Bang sono abilitati usando l'estensione della lingua BangPatterns 2010 BangPatterns .

Forme normali

Questo esempio fornisce una breve panoramica: per una spiegazione più approfondita delle forme e degli esempi normali , vedi questa domanda .

Forma normale ridotta

La forma normale ridotta (o semplicemente la forma normale, quando il contesto è chiaro) di un'espressione è il risultato della valutazione di tutte le sottoespressioni riducibili nell'espressione data. A causa della semantica non rigida di Haskell (tipicamente chiamata pigrizia ), una sottoespressione non è riducibile se si trova sotto un raccoglitore (cioè un'astrazione lambda - \x -> .. ). La forma normale di un'espressione ha la proprietà che, se esiste, è unica.

In altre parole, non importa (in termini di semantica denotazionale) in quale ordine riduci le sottoespressioni. Tuttavia, la chiave per scrivere programmi performanti Haskell è spesso garantire che l'espressione corretta venga valutata al momento giusto, ovvero la comprensione della semantica operazionale.

Un'espressione la cui forma normale è essa stessa si dice che sia in una forma normale .

Alcune espressioni, ad es let x = 1:x in x , non hanno una forma normale, ma sono comunque produttive. L'espressione di esempio ha ancora un valore , se si ammettono valori infiniti, che qui è la lista [1,1, ...] . Altre espressioni, come ad esempio let y = 1+y in y , non hanno valore, o il loro valore undefined è undefined .

Forma normale della testa debole

L'RNF corrisponde alla valutazione completa di un'espressione - allo stesso modo, la forma normale della testa debole (WHNF) corrisponde alla valutazione della testa dell'espressione. La testa di un'espressione e viene valutata completamente se e è un'applicazione Con e1 e2 .. en e Con è un costruttore; o un'astrazione \x -> e1 ; o un'applicazione parziale f e1 e2 .. en , dove l'applicazione parziale significa che f richiede più di n argomenti (o in modo equivalente, il tipo di e è un tipo di funzione). In ogni caso, le sottoespressioni e1..en possono essere valutate o non valutate perché l'espressione sia in WHNF - possono anche essere undefined .

La semantica di valutazione di Haskell può essere descritta in termini di WHNF - per valutare un'espressione e , prima valutarla in WHNF, quindi valutare ricorsivamente tutte le sue sottoespressioni da sinistra a destra.

La funzione seq primitiva viene utilizzata per valutare un'espressione di WHNF. seq xy è denotazionalmente uguale a y (il valore di seq xy è precisamente y ); inoltre x viene valutato in WHNF quando y viene valutato in WHNF. Un'espressione può anche essere valutata a WHNF con un modello di scoppio (abilitato dall'estensione -XBangPatterns ), la cui sintassi è la seguente:

f !x y = ... 

In cui x sarà valutato in WHNF quando si valuta f , mentre y non è (necessariamente) valutato. Un modello bang può anche apparire in un costruttore, ad es

data X = Con A !B C .. N

nel qual caso il costruttore Con si dice che sia rigoroso nel campo B , il che significa che il campo B viene valutato in WHNF quando il costruttore viene applicato a sufficienti (qui, due) argomenti.

Modelli pigri

I pattern pigri o irrefutabili (indicati con la sintassi ~pat ) sono schemi che corrispondono sempre, senza nemmeno guardare al valore corrispondente. Ciò significa che i pattern pigri corrisponderanno anche ai valori inferiori. Tuttavia, gli usi successivi di variabili legate a sub-pattern di un pattern irrefutabile costringeranno la corrispondenza del pattern a verificarsi, valutando in basso a meno che la corrispondenza non abbia esito positivo.

La seguente funzione è lazy nel suo argomento:

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

e così otteniamo

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

La seguente funzione è scritta con un pattern lazy ma in realtà utilizza la variabile del pattern che forza la corrispondenza, quindi fallirà per gli argomenti 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 legami sono pigri, si comportano come schemi irrefutabili:

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

Qui act1 funziona su input che analizzano qualsiasi elenco di stringhe, mentre in act2 il putStrLn s1 bisogno del valore di s1 che forza la corrispondenza del modello per [s1, s2] , quindi funziona solo per gli elenchi di esattamente due stringhe:

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

Campi rigorosi

In una dichiarazione di data , il prefisso di un tipo con un botto ( ! ) Rende il campo un campo rigoroso . Quando viene applicato il costruttore di dati, tali campi verranno valutati in forma normale deboli, pertanto i dati nei campi saranno sempre nella forma normale debole.

I campi rigorosi possono essere utilizzati sia nei tipi di record che di non record:

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
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow