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