Всегда ли шаблоны внутреннего взрыва заставляют внешних конструкторов в Haskell? - PullRequest
0 голосов
/ 19 декабря 2018

В Haskell существует ситуация, когда для типа данных

{-# LANGUAGE BangPatterns #-}
import Control.DeepSeq

data D = D Int

экземпляр

instance NFData D where
  rnf (D !_) = ()

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

instance NFData D where
  rnf !(D !_) = ()

Мое исследование:

  • https://downloads.haskell.org/~ghc/8.6.3/docs/html/users_guide/glasgow_exts.html#bang-patterns-informal говорит только о let привязках (например, этот ответ), о которых я думаюне применяется для совпадений с шаблонами функций, подобных этому.
  • https://prime.haskell.org/wiki/BangPatterns#Thebasicidea говорит

    Удар действительно имеет эффект, только если он предшествует переменной или дикому-карточный шаблон

    и

    , ставящий удар перед шаблоном, который в любом случае вызывает оценку, ничего не делает

    , и я думаю

    • rnf (D _) уже заставляет оценку в любом случае
      • , потому что это похоже на rnf x = case x of D _ -> ...
    • , поэтому rnf !(D _) будет иметь тот же эффект, что и rnf (D _)
    • и, следовательно, подстановка rnf !(D !_) должна иметь тот же эффект, что и rnf (D !_)

Так что я думаю нет, эти два всегда равныent , но я все равно прошу один очень четкий ответ, чтобы отсылать людей.

1 Ответ

0 голосов
/ 19 декабря 2018

Действительно, это правильно.Мы можем видеть, что оценивается, используя :sprint в GHCi, который показывает нам, что были оценены thunks.

Без шаблонов взрыва:

λ data D = D Int
λ d1 = D 1
λ :sprint d1
d1 = _
λ f1 (D _) = 0
λ f1 d1
0
λ :sprint d1
d1 = <D> _ -- Only D evaluated

С внутренним шаблоном взрыва:

λ d2 = D 2
λ :sprint d2
d2 = _
λ f2 (D !_) = 0
λ f2 d2
0
λ :sprint d2
d2 = <D> 2 -- Everything evaluated

С шаблоном внешнего взрыва:

λ d3 = D 3
λ :sprint d3
d3 = _
λ f3 !(D _) = 0
λ f3 d3
0
λ :sprint d3
d3 = <D> _ -- Only D evaluated

С шаблоном внутреннего и внешнего взрыва:

λ d4 = D 4
λ :sprint d4
d4 = _
λ f4 !(D !_) = 0
λ f4 d4
0
λ :sprint d4
d4 = <D> 4 -- Everything evaluated

Из этого легко увидеть, что шаблоны!(D !_) и (D !_) эквивалентны, и более того, шаблоны вида !(D ...) являются избыточными.

...