Szukaj…


Wzory Bang

Wzory opatrzone hukiem ( ! ) Są oceniane ściśle, a nie leniwie.

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

W tym przykładzie, x i z obydwie oceniane słabego główki normalnej formy przed powrotem do listy. Jest to równoważne z:

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

Wzorce Bang są włączane przy użyciu rozszerzenia języka BangPatterns Haskell 2010.

Normalne formy

Ten przykład zawiera krótki przegląd - aby uzyskać bardziej szczegółowe wyjaśnienie normalnych formularzy i przykładów, zobacz to pytanie .

Zredukowana postać normalna

Zredukowana postać normalna (lub po prostu postać normalna, gdy kontekst jest jasny) wyrażenia jest wynikiem oceny wszystkich redukowalnych podwyrażeń w danym wyrażeniu. Ze względu na surową semantykę Haskella (zwykle zwaną lenistwem ), podwyrażenie nie jest redukowalne, jeśli znajduje się pod spoiwem (tj. Abstrakcja lambda - \x -> .. ). Normalna forma wyrażenia ma tę właściwość, że jeśli istnieje, jest unikalna.

Innymi słowy, nie ma znaczenia (w kategoriach semantyki denotacyjnej), w jakiej kolejności zmniejsza się podwyrażenia. Jednak kluczem do pisania wydajnych programów Haskell jest często zapewnienie, że właściwe wyrażenie zostanie ocenione we właściwym czasie, tj. Zrozumienie semantyki operacyjnej.

Wyrażenie, którego normalna forma sama w sobie jest podobna, ma być w normalnej formie .

Niektóre wyrażenia, np. let x = 1:x in x , nie mają normalnej postaci, ale nadal są produktywne. Przykładowe wyrażenie nadal ma wartość , jeśli dopuszcza się wartości nieskończone, którymi jest lista [1,1, ...] . Inne wyrażenia, takie jak let y = 1+y in y , nie mają wartości lub ich wartość jest undefined .

Słaba głowa normalna forma

W pełni odpowiada RNF do oceny wyrażenie - podobnie słabe głowica normalnie postać (WHNF) odpowiada ocenie na głowę ekspresji. Początek wyrażenia e jest w pełni oceniany, jeśli e jest aplikacją Con e1 e2 .. en a Con jest konstruktorem; lub abstrakcja \x -> e1 ; lub częściowa aplikacja f e1 e2 .. en , gdzie częściowa aplikacja oznacza, że f przyjmuje więcej niż n argumentów (lub równoważnie, typ e jest typem funkcji). W każdym razie podwyrażenia e1..en mogą być ocenione lub nieocenione, aby wyrażenie było w WHNF - mogą nawet być undefined .

Semantyka oceny Haskella można opisać w kategoriach WHNF - aby ocenić wyrażenie e , najpierw oceń je do WHNF, a następnie rekurencyjnie oceń wszystkie jego podwyrażenia od lewej do prawej.

Pierwotna funkcja seq służy do oceny wyrażenia na WHNF. seq xy jest denotacyjnie równy y (wartość seq xy jest dokładnie y ); ponadto x jest oceniane na WHNF, gdy y jest oceniane na WHNF. Wyrażenie można również ocenić na WHNF za pomocą wzorca huku (włączonego przez rozszerzenie -XBangPatterns ), którego składnia jest następująca:

f !x y = ... 

W którym x zostanie oszacowane do WHNF, gdy f jest obliczone, podczas gdy y nie jest (koniecznie) oszacowane. Wzór huku może również pojawić się w konstruktorze, np

data X = Con A !B C .. N

w którym to przypadku mówi się, że konstruktor Con jest ścisły w polu B , co oznacza, że pole B jest oceniane dla WHNF, gdy konstruktor jest zastosowany do wystarczających (tutaj dwóch) argumentów.

Leniwe wzory

Leniwe lub niepodważalne wzorce (oznaczone składnią ~pat ) to wzorce, które zawsze pasują, nawet nie patrząc na dopasowaną wartość. Oznacza to, że leniwe wzorce będą pasowały nawet do najniższych wartości. Jednak kolejne użycie zmiennych powiązanych w pod-wzorach niepodważalnego wzorca wymusi dopasowanie wzorca, dokonując oceny na dole, chyba że dopasowanie się powiedzie.

Następująca funkcja jest leniwa w swoim argumencie:

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

i tak otrzymujemy

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

Poniższa funkcja jest napisana z leniwym wzorcem, ale w rzeczywistości używa zmiennej wzorca, która wymusza dopasowanie, więc nie powiedzie się dla argumentów 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 wiązania są leniwe, zachowuj się jak niepodważalne wzorce:

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

Tutaj act1 działa na danych wejściowych, które analizują dowolną listę ciągów, podczas gdy w act2 putStrLn s1 potrzebuje wartości s1 która wymusza dopasowanie wzorca dla [s1, s2] , więc działa tylko dla list dokładnie dwóch ciągów:

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

Surowe pola

W deklaracji data poprzedzenie typu hukiem ( ! ) Powoduje, że pole jest polem ścisłym . Po zastosowaniu konstruktora danych pola te zostaną ocenione do postaci normalnej o słabej głowie, więc gwarantuje się, że dane w polach będą zawsze w postaci normalnej o słabej głowie.

Pola ścisłe mogą być używane zarówno w typach rekordowych, jak i nie rekordowych:

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
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow