Haskell Language
stränghet
Sök…
Bang-mönster
Mönster som är annoterade med ett bang ( !
) Utvärderas strikt istället för lata.
foo (!x, y) !z = [x, y, z]
I det här exemplet utvärderas båda x
och z
till svag huvudformell form innan listan returneras. Det motsvarar:
foo (x, y) z = x `seq` z `seq` [x, y, z]
Bang-mönster aktiveras med hjälp av BangPatterns
Haskell 2010 BangPatterns
.
Normala former
Detta exempel ger en kort översikt - för en mer djupgående förklaring av normala former och exempel, se denna fråga .
Minskad normal form
Den minskade normala formen (eller bara normal form, när sammanhanget är klart) för ett uttryck är resultatet av utvärdering av alla reducerbara subexpressions i det givna uttrycket. På grund av den icke-strikta semantiken för Haskell (vanligtvis kallad latskap ) kan en subexpression inte reduceras om den är under ett bindemedel (dvs. en lambda-abstraktion - \x -> ..
). Den normala formen för ett uttryck har den egenskapen att om det finns är det unikt.
Med andra ord, det spelar ingen roll (i termer av denotational semantik) i vilken ordning du minskar subexpressions. Men nyckeln till att skriva performanta Haskell-program är ofta att säkerställa att rätt uttryck utvärderas vid rätt tidpunkt, dvs förståelsen av den operativa semantiken.
Ett uttryck vars normala form själva sägs vara i normal form .
Vissa uttryck, t.ex. let x = 1:x in x
, har ingen normal form, men är fortfarande produktiva. Exempeluttrycket har fortfarande ett värde , om man medger oändliga värden, som här är listan [1,1, ...]
. Andra uttryck, som let y = 1+y in y
, har inget värde, eller deras värde är undefined
.
Svag huvud normal form
De RNF motsvarar fullt utvärdera ett uttryck - likaså, den svaga huvudet normalform (WHNF) motsvarar utvärdera till huvudet av uttrycket. Huvudet för ett uttryck e
utvärderas fullständigt om e
är en applikation Con e1 e2 .. en
och Con
är en konstruktör; eller en abstraktion \x -> e1
; eller en partiell applikation f e1 e2 .. en
, där partiell applikation betyder att f
tar mer än n
argument (eller på motsvarande sätt är typen av e
en funktionstyp). I vilket fall som helst kan subexpressions e1..en
utvärderas eller utvärderas för att uttrycket ska vara i WHNF - de kan till och med undefined
.
Utvärderingssemantiken för Haskell kan beskrivas i termer av WHNF - för att utvärdera ett uttryck e
, först utvärdera det till WHNF och sedan rekursivt utvärdera alla dess underuttryck från vänster till höger.
Den primitiva seq
funktionen används för att utvärdera ett uttryck för WHNF. seq xy
är denotationellt lika med y
(värdet på seq xy
är exakt y
); vidare utvärderas x
till WHNF när y
utvärderas till WHNF. Ett uttryck kan också utvärderas till WHNF med ett bangmönster (aktiverat av förlängningen -XBangPatterns
), vars syntax är som följer:
f !x y = ...
I vilken x
kommer att utvärderas till WHNF när f
utvärderas, medan y
inte (nödvändigtvis) utvärderas. Ett bangmönster kan också visas i en konstruktör, t.ex.
data X = Con A !B C .. N
i vilket fall sägs konstruktören Con
vara strikt i B
fältet, vilket innebär att B
fältet utvärderas till WHNF när konstruktören appliceras på tillräckliga (här, två) argument.
Lata mönster
Lata eller oåterkalleliga mönster (betecknade med syntaxen ~pat
) är mönster som alltid matchar, utan att ens se på det matchade värdet. Detta betyder att lata mönster matchar jämna bottenvärden. Emellertid kommer efterföljande användningar av variabler bundna i undermönster i ett oåterkalleligt mönster att tvinga mönstermatchningen att ske, utvärdera till botten om inte matchen lyckas.
Följande funktion är lat i sitt argument:
f1 :: Either e Int -> Int
f1 ~(Right 1) = 42
och så får vi
λ» f1 (Right 1)
42
λ» f1 (Right 2)
42
λ» f1 (Left "foo")
42
λ» f1 (error "oops!")
42
λ» f1 "oops!"
*** type mismatch ***
Följande funktion är skriven med ett lat mönster men använder i själva verket mönsterets variabel som tvingar matchen, så kommer att misslyckas för 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
bindningar är lata, uppför sig som oåterkalleliga mönster:
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
Här act1
arbeten på insatser som parse någon lista med strängar, medan act2
den putStrLn s1
behov värdet av s1
vilka krafter mönstermatchning för [s1, s2]
, så det fungerar bara för listor över exakt två strängar:
λ» act1
> ["foo"]
Done
λ» act2
> ["foo"]
*** readIO: no parse ***
Stränga fält
I en data
förklaring prefix en typ med en smäll ( !
) Gör området en strikt fält. När datakonstruktören tillämpas kommer dessa fält att utvärderas till svag huvud normalform, så att data i fälten garanteras alltid att vara i svagt huvud normal form.
Stränga fält kan användas i både inspelnings- och icke-inspelningstyper:
data User = User
{ identifier :: !Int
, firstName :: !Text
, lastName :: !Text
}
data T = MkT !Int !Int