Что означает восклицательный знак в объявлении Haskell?

StackOverflow https://stackoverflow.com/questions/993112

  •  13-09-2019
  •  | 
  •  

Вопрос

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

data MidiMessage = MidiMessage !Int !MidiMessage
Это было полезно?

Решение

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

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

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

Функция f приведенное выше, при оценке, вернет "стук":то есть код, который нужно выполнить, чтобы определить его значение.На данный момент 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

Я считаю, что это примечание о строгости.

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top