291

実際のプロジェクトを使ってHaskellを学ぼうとすると、次の定義に出くわしました。それぞれの議論の前にある感嘆符が何を意味するのか理解できず、私の本はそれについて言及していないようでした。

data MidiMessage = MidiMessage !Int !MidiMessage
4

3 に答える 3

345

厳格宣言です。基本的には、データ構造の値を作成する際に、いわゆる「弱い頭の正規形」に評価する必要があるということです。これが何を意味するのかを理解できるように、例を見てみましょう。

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 が作成されます (存在しないと中を見ることができないため)。1 つ目は、テストしているので、4一致しないことがわかる まで評価する必要があります。

2 番目はテストしていないため、評価する必要はありません。したがって、そのメモリ ロケーションに保存するのではなく、6後で評価できるようにコードを保存します(3+3)。誰かがそれを見た場合にのみ、それは 6 になります。

ただし、3 番目のパラメーターは!前に があるため、厳密に評価されます。つまり(4+4)、実行8され、そのメモリ位置に格納されます。

4 番目のパラメーターも厳密に評価されます。しかし、ここで少しトリッキーになります。完全に評価するのではなく、弱い通常の頭の形だけを評価します。これは、それが何かであるかどうかを判断し、それを保存することを意味しますNothingJust、それ以上は行いません. つまりJust 10、実際には ではなく を格納Just (5+5)し、内部のサンクは評価せずに残します。これを知ることは重要ですが、これが意味することはすべて、この質問の範囲を超えていると思います.

BangPatterns言語拡張機能を有効にすると、同じ方法で関数の引数に注釈を付けることができます。

f x !y = x*y

f (1+1) (2+2)thunk を返し(1+1)*4ます。

于 2009-06-14T17:52:18.097 に答える
111

厳密なコンストラクター引数と厳密でないコンストラクター引数の違いを確認する簡単な方法は、未定義の場合の動作です。与えられた

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
于 2009-06-14T22:30:32.467 に答える
29

厳密さの注釈だと思います。

Haskellは純粋で怠惰な関数型言語ですが、怠惰のオーバーヘッドが多すぎたり無駄になったりすることがあります。したがって、これに対処するために、サンクを解析する代わりに、関数への引数を完全に評価するようにコンパイラーに要求できます。

このページには、パフォーマンス/厳密性に関する詳細情報があります。

于 2009-06-14T16:12:06.560 に答える