Поиск…


Шаблоны Bang

Шаблоны, аннотированные с ударом ( ! ), Оцениваются строго, а не лениво.

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

В этом примере x и z оба будут вычисляться до нормальной нормальной формы головы, прежде чем возвращать список. Это эквивалентно:

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

Шаблоны Bang активируются с использованием языкового расширения Haskell 2010 BangPatterns .

Нормальные формы

В этом примере приводится краткий обзор - для более подробного объяснения нормальных форм и примеров см. Этот вопрос .

Уменьшенная нормальная форма

Приведенная нормальная форма (или просто нормальная форма, когда контекст ясен) выражения является результатом оценки всех приводимых подвыражений в данном выражении. Из-за нестрогой семантики Haskell (обычно называемой лень ) подвыражение не может быть приводимым, если оно находится под связующим (т.е. абстракция лямбда - \x -> .. ). Нормальная форма выражения обладает тем свойством, что если оно существует, оно уникально.

Другими словами, это не имеет значения (в терминах денотационной семантики), в каком порядке вы уменьшаете подвыражения. Однако ключ к написанию исполняемых программ Haskell часто гарантирует, что правильное выражение оценивается в нужное время, т. Е. Понимание оперативной семантики.

Выражение, нормальная форма которого сама по себе, называется нормальной .

Некоторые выражения, например, let x = 1:x in x , не имеют нормальной формы, но все же продуктивны. Выражение выражения все еще имеет значение , если оно допускает бесконечные значения, которые представляют собой список [1,1, ...] . Другие выражения, такие как let y = 1+y in y , не имеют значения или их значение не undefined .

Нормальная форма слабой головы

RNF соответствует полной оценке выражения - аналогично, нормальная форма слабой головки (WHNF) соответствует оценке головы выражения. Глава выражения e полностью оценивается, если e - приложение Con e1 e2 .. en и Con - конструктор; или абстракции \x -> e1 ; или частичное приложение f e1 e2 .. en , где частичное приложение означает, что f принимает больше n аргументов (или, что эквивалентно, тип e является типом функции). В любом случае подвыражения e1..en могут быть оценены или не оценены для выражения в WHNF - они могут даже быть undefined .

Семантика оценки Haskell может быть описана в терминах WHNF - для оценки выражения e , сначала оцените его в WHNF, а затем рекурсивно оцените все его подвыражения слева направо.

Первоначальная функция seq используется для оценки выражения WHNF. seq xy денотационно равно y (значение seq xy точно равно y ); кроме того, x оценивается как WHNF, когда y оценивается WHNF. Выражение также может быть оценено в WHNF с шаблоном помех (активируется расширением -XBangPatterns ), синтаксис которого следующий:

f !x y = ... 

В котором x будет оцениваться в WHNF, когда f оценивается, а y не (обязательно) оценивается. Шаблон помех может также отображаться в конструкторе, например

data X = Con A !B C .. N

в этом случае конструктор Con считается строгим в поле B , что означает, что поле B оценивается как WHNF, когда конструктор применяется к достаточным (здесь, двум) аргументам.

Ленивые узоры

Ленивые или неопровержимые шаблоны (обозначаемые синтаксисом ~pat ) - это шаблоны, которые всегда совпадают, даже не рассматривая сопоставимое значение. Это означает, что ленивые шаблоны будут соответствовать даже нижним значениям. Однако последующее использование переменных, связанных в подструктурах неопровержимого шаблона, заставит совпадение шаблонов происходить, оценивая до дна, если совпадение не будет выполнено.

Следующая функция в своем аргументе ленива:

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

и поэтому мы получаем

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

Следующая функция написана с ленивым шаблоном, но на самом деле использует переменную шаблона, которая заставляет совпадение, поэтому не будет 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 привязки ленивы, ведут себя как неопровержимые шаблоны:

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

Здесь act1 работает на входах, которые анализируются на любой список строк, тогда как в act2 для putStrLn s1 требуется значение s1 которое заставляет совпадение шаблонов для [s1, s2] , поэтому оно работает только для списков ровно двух строк:

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

Строгие поля

В объявлении data префикс типа с bang ( ! ) Делает поле строгим полем . Когда применяется конструктор данных, эти поля будут вычисляться до нормальной нормальной формы головы, поэтому данные в полях гарантированно всегда будут в слабой нормальной форме головы.

Строгие поля могут использоваться как для записей, так и для не-записей:

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
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow