22title : Strict拡張を使用する際の注意点
33headingBackgroundImage : ../../img/background.png
44headingDivClass : post-heading
5- author : Yuji Yamamoto
6- postedBy : <a href="http://the.igreque.info/">Yuji Yamamoto (@igrep)</a>
5+ author : YAMAMOTO Yuji
6+ postedBy : <a href="http://the.igreque.info/">YAMAMOTO Yuji (@igrep)</a>
77date : January 26, 2020
88tags :
99...
@@ -19,7 +19,7 @@ Haskellは他の多くのプログラミング言語と異なった特徴を持
1919これらの拡張を大雑把に言うと、
2020
2121- ` StrictData ` : 値コンストラクターにおいて、引数の値が弱頭正規形(Weak Head Normal Form。以降慣習に従い「WHNF」と呼びます)まで評価されるようになる
22- - ` Strict ` : 値コンストラクターを含めたあらゆる関数やローカル変数の定義において、パターンマッチで束縛した変数の値がWHNFまで評価されるようになる
22+ - ` Strict ` : 値コンストラクターを含めたあらゆる関数やローカル変数の定義において、パターンマッチで代入した変数の値がWHNFまで評価されるようになる
2323
2424というものです。
2525
@@ -56,9 +56,59 @@ stack exec runghc -- <これから紹介するコードのファイル>.hs
5656
5757なお、使用したGHCのバージョンは8.6.5で、OSはWindows 10 ver. 1909です。
5858
59- # Case hoge : ` where ` 句だろうとなんだろうと評価
59+ # Case 1 : ` where ` 句だろうとなんだろうと評価
6060
61- hoge
61+ 最初のケースは、遅延評価で当たり前に享受していたメリットが、` Strict ` を有効にしている状態では得られなくなってしまう、というものです。
62+ [ pfxfncさんのStrict拡張でハマったお話] ( https://qiita.com/pxfnc/items/a26bda6d11402daba675 ) という記事でも紹介されてはいますが、まとめ記事なのでここでも改めて取り上げます。
63+
64+ ``` haskell
65+ main :: IO ()
66+ main = print $ div10 0
67+
68+ div10 :: Int -> Int
69+ div10 n
70+ | n == 0 = 0
71+ | otherwise = result
72+ where
73+ result = 10 `div` n
74+ ```
75+
76+ ご覧のとおり、本当にほとんどpfxfncさんの記事のサンプルそのままで恐縮ですが、このプログラム、👇のように` Strict ` 拡張を有効にして実行するとエラーが起こります。
77+
78+ ``` bash
79+ > stack exec -- runghc --ghc-arg=-XStrict where.hs
80+ where.hs: divide by zero
81+ ```
82+
83+ 一方、` Strict ` 拡張を有効にしなかった場合、エラーは起こりません。
84+
85+ ``` bash
86+ > stack exec -- runghc where.hs
87+ 0
88+ ```
89+
90+ なぜこんなことが起こるのでしょう?
91+
92+ これは、` Strict ` 拡張がパターンマッチで代入したあらゆる変数の値をWHNFまで評価するようになった結果、` where ` 句で代入した変数まで必ずWHNFまで評価してしまうために発生したエラーです。
93+ すなわち、` where ` における、
94+
95+ ``` haskell
96+ result = 10 `div` n
97+ ```
98+
99+ までもが、
100+
101+ ``` haskell
102+ ! result = 10 `div` n
103+ ```
104+
105+ とBangパターンを付けた代入であるかのように解釈されたのです[ ^ bangpatterns ] 。
106+
107+ [ ^ bangpatterns ] : ` BangPatterns ` 言語拡張を有効にした上で上記のように書き換えてみると、` Strict ` 拡張の有無に関わらずエラーが発生します。試してみましょう。
108+
109+ こうなると、` result ` を使用しないケース、すなわち` n == 0 = 0 ` の場合であっても` result ` に <small >(WHNFまで評価した)</small >値を代入するのに必要な計算は実行され、結果<code >10 ` div ` 0</code >が計算されようとして` divide by zero ` が発生するのです。
110+
111+ ` where ` 句は関数定義の後ろの方に書くという性格上、見落としがちかも知れません。注意しましょう。
62112
63113# Case hoge: ポイントフリースタイルかどうかで変わる!
64114
0 commit comments