7.19. アサーション

標準Haskellのコードでアサーションを使いたいなら、次のような関数を定義することができるだろう。

assert :: Bool -> a -> a
assert False x = error "assertion failed!"
assert _     x = x

これは動作するが、発生するエラーメッセージは全く役に立たない。アサーションが失敗した。よろしい。しかしどこのどれが失敗したのだ?

一つの解決策は、assertを拡張して、エラーメッセージに含める文字列を受け取るようにし、例えばソース中でassertが使われている場所にソース位置を挿入する前処理器と組み合わせることである。

GHCはこれに対して救いの手を差しのべる。これら全てを代わりに行うことによって。ユーザのソースにおいてassertが使われているところ全てに対して、以下の処理を行う。

kelvinToC :: Double -> Double
kelvinToC k = assert (k >= 0.0) (k+273.15)

上のようなものがあったとき、これを、アサーションが行われた地点を含むように書き換える。

assert pred val ==> assertError "Main.hs|15" pred val

このような書き換えが行われるのは、コンパイラがControl.Exception.assertの適用を見つけたときだけである。したがって、もし望むなら、自分で定義したassertを使うこともできる。そうでないなら、assertを使うときはControl.Exceptionをインポートせよ。

GHCは、-Oフラグで最適化が有効になっていると、アサーションを無視する。つまり、assert pred eという形の式はeに書き換えられる。-fignore-assertsオプションを使ってアサーションを無効にすることもできる。-fno-ignore-assertsオプションを使うと、最適化が有効な時でもアサーションを有効にしておくことができる。

アサーションの失敗は補足することができる。詳細はControl.Exceptionの説明書きを見よ。