To deklaracja ścisłości. Zasadniczo oznacza to, że należy go ocenić do tak zwanej „postaci normalnej słabej głowy” podczas tworzenia wartości struktury danych. Spójrzmy na przykład, abyśmy mogli zobaczyć, co to znaczy:
data Foo = Foo Int Int !Int !(Maybe Int)
f = Foo (2+2) (3+3) (4+4) (Just (5+5))
Powyższa funkcja f
po ocenie zwróci „thunk”: kod, który należy wykonać, aby obliczyć jego wartość. W tym momencie Foo jeszcze nie istnieje, tylko kod.
Ale w pewnym momencie ktoś może spróbować zajrzeć do środka, prawdopodobnie poprzez dopasowanie wzoru:
case f of
Foo 0 _ _ _ -> "first arg is zero"
_ -> "first arge is something else"
Spowoduje to wykonanie kodu wystarczającego do zrobienia tego, czego potrzebuje, i nic więcej. Stworzy to Foo z czterema parametrami (ponieważ nie możesz zajrzeć do niego bez jego istnienia). Po pierwsze, odkąd go testujemy, musimy ocenić aż do miejsca 4
, w którym zdajemy sobie sprawę, że nie pasuje.
Drugiego nie trzeba oceniać, ponieważ go nie testujemy. Tak więc, zamiast 6
być przechowywane w tej lokalizacji pamięci, będziemy po prostu zapisać kod do ewentualnej późniejszej oceny (3+3)
. To zmieni się w 6 tylko wtedy, gdy ktoś na to spojrzy.
Trzeci parametr ma jednak !
przed sobą, więc jest ściśle oceniany: (4+4)
jest wykonywany i 8
jest przechowywany w tym miejscu pamięci.
Czwarty parametr jest również ściśle oceniany. Ale tutaj jest nieco trudniej: oceniamy nie w pełni, ale tylko do słabej normalnej postaci głowy. Oznacza to, że ustalamy, czy to, Nothing
czy Just
coś, i przechowujemy to, ale nie idziemy dalej. Oznacza to, że przechowujemy nie, Just 10
ale faktycznie Just (5+5)
, pozostawiając thunk w środku nieocenionym. To ważne, aby wiedzieć, choć uważam, że wszystkie implikacje tego wykraczają poza zakres tego pytania.
Możesz opisać argumenty funkcji w ten sam sposób, jeśli włączysz BangPatterns
rozszerzenie języka:
f x !y = x*y
f (1+1) (2+2)
zwróci thunk (1+1)*4
.