Haskell Language
厳密さ
サーチ…
バンパターン
bang( ! )で注釈が付けられたパターンは、遅延の代わりに厳密に評価されます。
foo (!x, y) !z = [x, y, z]
この例では、リストを返す前にxとz両方がweak head normal formに評価されます。それは以下と同じです:
foo (x, y) z = x `seq` z `seq` [x, y, z]
Bangパターンは、Haskell 2010 BangPatterns言語拡張を使用して有効にします。
標準フォーム
この例では、簡単な概要を示します。 通常のフォームと例の詳細な説明は、 この質問を参照してください。
通常のフォームの縮小
式の縮小された正規形(または文脈が明らかである場合には通常の形)は、与えられた式のすべての縮小可能な部分式を評価した結果です。 Haskellの非厳密な意味論(通常は怠惰と呼ばれる)のために、サブ表現はバインダーの下にある場合(つまり、ラムダ抽象化 - \x -> .. )、還元できません。式の通常の形式は、存在する場合は一意であるという性質を持つ。
言い換えれば、部分表現を減らす順序(意味論的意味論の観点から)は関係ありません。しかし、パフォーマンスの良いHaskellプログラムを書くための鍵は、正しい表現が適切なタイミングで評価されること、つまり操作上のセマンティクスを理解することを保証することです。
その正規形そのもので発現が正常な形態にあると言われます。
いくつかの式、たとえばlet x = 1:x in xは、通常の形を持ちませんが、まだ生産的です。無限の値が許される場合 、例の式はまだ値を持っています 。ここではリスト[1,1, ...]です。 let y = 1+y in yなどの他の式は値を持たないか、その値はundefinedです。
弱い頭の普通形
RNFは式を完全に評価することに対応します。同様に、弱い頭部標準形(WHNF)は式の先頭を評価することに対応します。式のヘッドeあれば十分に評価されeアプリケーションであるCon e1 e2 .. enおよびConコンストラクタです。または抽象化\x -> e1 ;または部分アプリケーションf e1 e2 .. en部分アプリケーション手段、 f以上かかるn引数(又は等価的に、タイプe関数型です)。いずれにしても、部分式e1..enはe1..enにある式e1..en評価されるか評価されundefined 。 undefinedあっても可能です。
ハスケルの評価セマンティクスはWHNFの形で記述することができます。式eを評価し、まずそれをWHNFに評価し、その後、すべての部分式を左から右に再帰的に評価します。
プリミティブseq関数は、式をWHNFに評価するために使用されます。 seq xyにdenotationally等しく、 y (の値seq xy正確でありy )さらに、 yがWHNFと評価されるとき、 xはWHNFと評価される。式は、(- -XBangPatterns拡張によって有効になる)bangパターンでWHNFに評価することもできます。その構文は次のとおりです。
f !x y = ...
fが評価されたときにxはWHNFに評価され、 yは(必然的に)評価されません。 bangパターンはコンストラクタにも現れます。
data X = Con A !B C .. N
この場合、コンストラクタConはBフィールドで厳密であると言われます。これは、コンストラクタが十分な(ここでは2つの)引数に適用されたときにBフィールドがWHNFに評価されることを意味します。
レイジーパターン
(構文で示さレイジー、または反駁 、パターン~pat )も、常にマッチした値を見ずに、一致するパターンです。これは、遅延パターンがボトム値にも一致することを意味します。しかし、反駁不能なパターンのサブパターンに束縛された変数のその後の使用は、マッチが成功しない限り、パターンマッチングを強制的に実行し、最下位に評価する。
次の関数は引数に怠惰です。
f1 :: Either e Int -> Int
f1 ~(Right 1) = 42
それで
λ» f1 (Right 1)
42
λ» f1 (Right 2)
42
λ» f1 (Left "foo")
42
λ» f1 (error "oops!")
42
λ» f1 "oops!"
*** type mismatch ***
次の関数は、遅延パターンで書かれていますが、実際には一致を強制するパターンの変数を使用しているため、 Left引数では失敗します。
f2 :: Either e Int -> Int
f2 ~(Right x) = x + 1
λ» f2 (Right 1)
2
λ» f2 (Right 2)
3
λ» f2 (Right (error "oops!"))
*** Exception: oops!
λ» f2 (Left "foo")
*** Exception: lazypat.hs:5:1-21: Irrefutable pattern failed for pattern (Right x)
λ» f2 (error "oops!")
*** Exception: oops!
letバインディングは、のように反論できないパターンを怠惰に動作しています:
act1 :: IO ()
act1 = do
ss <- readLn
let [s1, s2] = ss :: [String]
putStrLn "Done"
act2 :: IO ()
act2 = do
ss <- readLn
let [s1, s2] = ss
putStrLn s1
ここact1中のに対し、文字列の任意のリストに解析した入力に動作しますact2 putStrLn s1の値必要s1のためのパターンマッチング強制的に[s1, s2] 、ので、それだけで正確に二つの文字列のリストに対して動作します。
λ» act1
> ["foo"]
Done
λ» act2
> ["foo"]
*** readIO: no parse ***
厳密なフィールド
data宣言では、型の前にバング( ! )を付けると、フィールドは厳密なフィールドになります 。データコンストラクタが適用されると、これらのフィールドは弱いヘッドノーマルフォームに評価されるので、フィールドのデータは常に弱いヘッドノーマルフォームになることが保証されます。
厳密なフィールドは、レコード型と非レコード型の両方で使用できます。
data User = User
{ identifier :: !Int
, firstName :: !Text
, lastName :: !Text
}
data T = MkT !Int !Int