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


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

data MidiMessage = MidiMessage !Int !MidiMessage
3 222

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

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