回答:
それは厳格な宣言です。基本的には、データ構造の値が作成されるときに、「弱い頭の正規形」と呼ばれるものに評価される必要があることを意味します。これが何を意味するのかがわかるように、例を見てみましょう。
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"
これにより、必要なことを実行するのに十分なコードが実行されます。したがって、4つのパラメータを持つFooが作成されます(Fooが存在しないと内部を見ることができないため)。1つ目は、テストしているため、すべての方法を評価する必要があります。4
、が一致しないことに気づくます。
2番目はテストしないので、評価する必要はありません。したがって、6
そのメモリ位置に保存されるのではなく、後で評価できるようにコードを保存します(3+3)
。誰かがそれを見る場合にのみ、それは6に変わります。
ただし、3番目のパラメーターの!
前にはがあるため、厳密に評価されます。(4+4)
実行8
され、そのメモリー位置に格納されます。
4番目のパラメーターも厳密に評価されます。ただし、ここで少し注意が必要です。完全に評価するのではなく、弱い通常の頭の形のみを評価しています。我々は、それはだかどうかを把握することをこれが意味Nothing
かJust
という何か、と店が、我々はそれ以上に行くん。つまりJust 10
、実際に保存するのではなくJust (5+5)
に、サンクを評価ます。これは知っておくべき重要なことですが、これによるすべての影響は、この質問の範囲を超えていると思います。
BangPatterns
言語拡張機能を有効にすると、同じ方法で関数の引数に注釈を付けることができます。
f x !y = x*y
f (1+1) (2+2)
サンクを返し(1+1)*4
ます。
seq
です。
厳密なコンストラクタ引数と厳密でないコンストラクタ引数の違いを確認する簡単な方法は、未定義の場合の動作です。与えられた
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
!
、内部実装の詳細を掘り下げるのではなく、シンボルが持つユーザー観察可能な効果を実際に説明するため、Curt Sampsonの回答よりも優れています。
厳密な注釈だと思います。
Haskellは純粋で遅延のある関数型言語ですが、遅延のオーバーヘッドが多すぎたり無駄になったりする場合があります。したがって、それに対処するには、サンクを解析する代わりに、関数の引数を完全に評価するようコンパイラーに要求できます。
このページには、パフォーマンス/厳密性に関する詳細情報があります。
map Just [1,2,3]
[Just 1、Just 2、Just 3]を取得するなど)。それらとパターンマッチングを行う機能と、まったく関連のない機能について考えるとわかりやすいでしょう。