Zoeken…


Bang patronen

Patronen geannoteerd met een knal ( ! ) Worden strikt geëvalueerd in plaats van lui.

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

In dit voorbeeld worden x en z beide geëvalueerd naar de normale vorm van een zwakke kop voordat de lijst wordt geretourneerd. Het is gelijk aan:

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

Bang-patronen worden ingeschakeld met de BangPatterns Haskell 2010 BangPatterns .

Normale vormen

Dit voorbeeld biedt een kort overzicht - zie deze vraag voor een meer diepgaande uitleg van normale vormen en voorbeelden.

Verminderde normale vorm

De verminderde normale vorm (of gewoon normale vorm, wanneer de context duidelijk is) van een uitdrukking is het resultaat van het evalueren van alle reduceerbare subexpressies in de gegeven uitdrukking. Vanwege de niet-strikte semantiek van Haskell (meestal luiheid genoemd ), kan een subexpressie niet worden gereduceerd als deze zich onder een binder bevindt (dwz een lambda-abstractie - \x -> .. ). De normale vorm van een uitdrukking heeft de eigenschap dat als deze bestaat, deze uniek is.

Met andere woorden, het maakt niet uit (in termen van denotationele semantiek) in welke volgorde u subexpressies vermindert. De sleutel tot het schrijven van performante Haskell-programma's is echter vaak ervoor zorgen dat de juiste expressie op het juiste moment wordt geëvalueerd, dwz het begrijpen van de operationele semantiek.

Van een uitdrukking waarvan de normale vorm zelf is, wordt gezegd dat deze in normale vorm is .

Sommige uitdrukkingen, bijvoorbeeld let x = 1:x in x , hebben geen normale vorm, maar zijn nog steeds productief. De voorbeelduitdrukking heeft nog steeds een waarde , als men oneindige waarden toelaat, wat hier de lijst is [1,1, ...] . Andere uitdrukkingen, zoals let y = 1+y in y , hebben geen waarde of hun waarde is undefined .

Zwak hoofd normale vorm

De RNF komt overeen met het volledig evalueren van een uitdrukking - evenzo komt de normale vorm van de zwakke kop (WHNF) overeen met het evalueren van de kop van de uitdrukking. De kop van een uitdrukking e wordt volledig geëvalueerd als e een toepassing is Con e1 e2 .. en en Con is een constructor; of een abstractie \x -> e1 ; of een gedeeltelijke toepassing f e1 e2 .. en , waar gedeeltelijke toepassing betekent dat f meer dan n argumenten nodig heeft (of equivalent, het type e is een functietype). In elk geval kunnen de subexpressies e1..en worden geëvalueerd of niet geëvalueerd voor de uitdrukking in WHNF - ze kunnen zelfs undefined .

De evaluatie-semantiek van Haskell kan worden beschreven in termen van de WHNF - om een uitdrukking e te evalueren, deze eerst te evalueren naar WHNF en vervolgens recursief alle subexpressies van links naar rechts te evalueren.

De primitieve seq functie wordt gebruikt om een uitdrukking naar WHNF te evalueren. seq xy is denotationeel gelijk aan y (de waarde van seq xy is precies y ); verder wordt x geëvalueerd tot WHNF wanneer y wordt geëvalueerd tot WHNF. Een uitdrukking kan ook worden geëvalueerd naar WHNF met een knalpatroon (ingeschakeld door de extensie -XBangPatterns ), waarvan de syntaxis als volgt is:

f !x y = ... 

Waarin x wordt geëvalueerd naar WHNF wanneer f wordt geëvalueerd, terwijl y niet (noodzakelijkerwijs) wordt geëvalueerd. Een knalpatroon kan ook in een constructor verschijnen, bijvoorbeeld

data X = Con A !B C .. N

in dat geval wordt gezegd dat de constructor Con strikt is in het B veld, wat betekent dat het B veld wordt geëvalueerd naar WHNF wanneer de constructor wordt toegepast op voldoende (hier twee) argumenten.

Luie patronen

Luie of onweerlegbare patronen (aangeduid met de syntaxis ~pat ) zijn patronen die altijd overeenkomen, zonder zelfs naar de overeenkomende waarde te kijken. Dit betekent dat luie patronen overeenkomen met zelfs onderste waarden. Volgend gebruik van variabelen die zijn gebonden in subpatronen van een onweerlegbaar patroon, dwingt de patroonovereenkomst echter tot de bodem, tenzij de overeenkomst slaagt.

De volgende functie is lui in zijn argument:

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

en zo krijgen we

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

De volgende functie is geschreven met een lui patroon, maar gebruikt in feite de variabele van het patroon die de overeenkomst forceert, dus mislukt voor Left argumenten:

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 bindingen lui zijn, gedraag je als onweerlegbare patronen:

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

Hier werkt act1 op ingangen die parseren naar een lijst met strings, terwijl in act2 de putStrLn s1 de waarde van s1 die de patroonovereenkomst voor [s1, s2] forceert, dus het werkt alleen voor lijsten met exact twee strings:

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

Strikte velden

In een data maakt het voorvoegsel van een type met een knal ( ! ) Het veld een strikt veld . Wanneer de gegevensconstructor wordt toegepast, zullen die velden worden geëvalueerd in de normale vorm van de zwakke kop, dus de gegevens in de velden zijn gegarandeerd altijd in de normale vorm van de zwakke kop.

Strikte velden kunnen worden gebruikt in zowel record- als niet-recordtypen:

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
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow