実行時へ型エラーを遅らせる
開発中,コードに型エラーがあってもコンパイルを成功させることを許すのが望ましい場合がある.以下の例を考えてみよう:
code: defer1.hs
module Main where
a :: Int
a = 'a'
main = print "b"
aの型がill-typedであっても,最終的には使われない.そのため,我々が関心を持つのがmainだけであれば,aの問題は無視できると便利なことがある.
さらなるモチベーションと詳細に関しては, Wikiのページや原論文を参照せよ. 型エラーの遅延の有効化
-fdefer-type-errors フラグは,型エラーを実行時へと遅らせるかどうかを制御する.型エラーはそれでも警告として出力されるが,コンパイルは妨げない. -Wno-type-errors を使うことでこれらの警告を抑制できる.
このフラグは, -fdefer-typed-holesフラグと-fdefer-out-of-scope-variablesフラグを含む.これにより,型付き穴及び変数に対して,この機能が有効になる.万が一したいなら,-fdefer-type-errors フラグを有効にした後に,コマンドライン上で -fno-defer-typed-holes や-fno-defer-out-of-scope-variablesを明示的に指定することで, -fdefer-typed-holesや-fdefer-out-of-scope-variablesを有効にせずに,-fdefer-type-errorsを有効にすることができる.
実行時に,型エラーを含む項を評価する必要がある場合はいつでも,エラーはTypeError型の実行時例外に変換される.型エラーは実行時へと可能な限り遅延されるが,最終的には正しい型の値になる場合であっても無効なcoercionは実行されないことに注意せよ.例えば,以下の例がある:
code:defer2.hs
x :: Int
x = 0
y :: Char
y = x
z :: Int
z = y
zを評価すると実行時TypeErrorになる.
GHCiでの型エラーの遅延
-fdefer-type-errorsフラグはGHCiにおいても動作するが,唯一の例外がある.プロンプトに入力された「裸の」式に対しては型エラーは遅延されない.ゆえに,例えば
code:defer3
Prelude> fst (True, 1 == 'a')
<interactive>:2:12:
No instance for (Num Char) arising from the literal `1'
Possible fix: add an instance declaration for (Num Char)
In the first argument of (==)', namely 1'
In the expression: 1 == 'a'
In the first argument of fst', namely (True, 1 == 'a')'
こうしないと,プロンプトでreverse Trueとタイプするといったよくある単純な型エラーのケースで,式が評価されたときに警告が出て直後に型エラーが出てしまい,不便だからである.
次の例が示すように,この例外は文に対しては適用されない.
code:defer4
Prelude> let x = (True, 1 == 'a')
<interactive>:3:16: Warning:
No instance for (Num Char) arising from the literal `1'
Possible fix: add an instance declaration for (Num Char)
In the first argument of (==)', namely 1'
In the expression: 1 == 'a'
In the expression: (True, 1 == 'a')
Prelude> fst x
True
(訳注:上記のコードは,GHCiのバージョンアップに伴いletなしでも動くようになっている.)
型エラーの遅延の制約
遅延させることができるエラーは:
スコープ外の値レベルの変数
等価制約. 例えば, ord Trueは解決不能な等価制約 Char ~ Boolを生むが,これがエラーになるのを実行時へと遅らせることができる.
型クラスと暗黙のパラメータの制約
これ以外の型エラーは全て即座に報告され,遅らせることはできない.例としては,ill-kindedな型シグネチャ・非決定的だったりill-formedだったりするインスタンス宣言・宣言された単射性制約に従わない型族インスタンス・などなどがある.
一部の場合では,等価制約であっても実行時へと遅らせることができない.具体的には、
種等式は遅らせることができない.例えば,
code:defer5.hs
f :: Int Bool -> Char
この型シグネチャは種エラーを含むが,これは実行時へと遅らせることができない.
forallの下の型等式(Type equalities)は遅らせることができない(Trac \#14605を参照せよ).