Что означает восклицательный знак в декларации Haskell?

я наткнулся на следующее определение, когда я пытаюсь изучить Haskell, используя реальный проект для его управления. Я не понимаю, что означает восклицательный знак перед каждым аргументом, и мои книги, казалось, не упоминали об этом.

data MidiMessage = MidiMessage !Int !MidiMessage

3 ответов


это декларация строгости. В принципе, это означает, что при создании значения структуры данных оно должно оцениваться до так называемой "слабой нормальной формы головы". Давайте рассмотрим пример, чтобы понять, что это значит:

data Foo = Foo Int Int !Int !(Maybe Int)

f = Foo (2+2) (3+3) (4+4) (Just (5+5))

функции f выше, при оценке, вернет "thunk": то есть код для выполнения, чтобы выяснить его значение. В этот момент Foo еще даже не существует, только код.

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

case f of
     Foo 0 _ _ _ -> "first arg is zero"
     _           -> "first arge is something else"

это будет выполнять достаточно кода, чтобы делать то, что ему нужно, и не более. Таким образом, он создаст Foo с четырьмя параметрами (потому что вы не можете заглянуть внутрь него без его существования). Во-первых, поскольку мы тестируем его, нам нужно оценить весь путь до 4, где мы понимаем, что это не соответствует.

второй не нужно оценивать, потому что мы его не тестируем. Таким образом, вместо 6 будучи сохраненный в этом месте памяти, мы просто сохраним код для возможной последующей оценки,(3+3). Это превратится в 6, только если кто-то посмотрит на него.

третий параметр, однако, имеет ! перед ним, поэтому строго оценивается:(4+4) выполнено, и 8 хранится в этой памяти.

четвертый параметр также строго оценивается. Но вот где это становится немного сложнее: мы оцениваем не полностью, а только слабую нормальную форму головы. Это означает, что мы выясним, является ли это Nothing или Just что-то, и хранить это, но мы не идем дальше. Это означает, что мы храним не Just 10 но на самом деле Just (5+5), оставляя удар внутри недооцененным. Это важно знать, хотя я думаю, что все последствия этого выходят за рамки данного вопроса.

вы можете комментировать аргументы функции таким же образом, если вы включите BangPatterns язык расширение:

f x !y = x*y

f (1+1) (2+2) вернет thunk (1+1)*4.


простой способ увидеть разницу между строгими и нестрогими аргументами конструктора-это то, как они ведут себя, когда они не определены. Дано

data Foo = Foo Int !Int

first (Foo x _) = x
second (Foo _ y) = y

поскольку нестрогий аргумент не оценивается second, проходящей в undefined не вызывает проблем:

> second (Foo undefined 1)
1

но строгий аргумент не может быть undefined, даже если мы не используем значение:

> first (Foo 1 undefined)
*** Exception: Prelude.undefined

Я считаю, что это аннотация строгости.

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

на этой странице есть дополнительная информация:Производительность/Строгость.