内部爆炸模式是否总是在 Haskell 中强制外部构造函数?
Do inner bang patterns always force outer constructors in Haskell?
在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 only talks about
let
bindings (like this 回答),我认为这不适用于像这样的函数模式匹配。
https://prime.haskell.org/wiki/BangPatterns#Thebasicidea 说
A bang only really has an effect if it precedes a variable or wild-card pattern
和
putting a bang before a pattern that forces evaluation anyway does nothing
而且我认为
rnf (D _)
已经强制求值了
- 因为它就像
rnf x = case x of D _ -> ...
- 所以
rnf !(D _)
与 rnf (D _)
的效果相同
- 因此通过替换
rnf !(D !_)
必须具有与 rnf (D !_)
相同的效果
所以我认为不,这两个总是等价的,但无论如何我还是要问一个非常明确的答案以供参考。
的确如此。我们可以看到在 GHCi
中使用 :sprint
评估了什么,它向我们展示了哪些 thunk 已被评估。
没有刘海图案:
λ 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 ...)
形式的模式是多余的。
在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 only talks about
let
bindings (like this 回答),我认为这不适用于像这样的函数模式匹配。 https://prime.haskell.org/wiki/BangPatterns#Thebasicidea 说
A bang only really has an effect if it precedes a variable or wild-card pattern
和
putting a bang before a pattern that forces evaluation anyway does nothing
而且我认为
rnf (D _)
已经强制求值了- 因为它就像
rnf x = case x of D _ -> ...
- 因为它就像
- 所以
rnf !(D _)
与rnf (D _)
的效果相同
- 因此通过替换
rnf !(D !_)
必须具有与rnf (D !_)
相同的效果
所以我认为不,这两个总是等价的,但无论如何我还是要问一个非常明确的答案以供参考。
的确如此。我们可以看到在 GHCi
中使用 :sprint
评估了什么,它向我们展示了哪些 thunk 已被评估。
没有刘海图案:
λ 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 ...)
形式的模式是多余的。