7.15. 型エラーを実行時まで遅らせる

開発中、コードに型エラーがあるにもかかわらずコンパイルが成功できるようにするのが望ましいことがある。次の例を考えよ。

module Main where

a :: Int
a = 'a'

main = print "b"

aの型は間違っているが、最終的には使われていないので、mainのことしか気にしないなら、aについての問題を無視できると便利かもしれない。

さらなる動機付けと詳細については、HaskellWikiのページか、原論文を見よ。

7.15.1. 型エラーの遅延を有効にする

-fdefer-type-errorsフラグは、型エラーを実行時まで遅らせるかどうかを制御する。型エラーはなお警告として出力されるが、コンパイルを止めることはない。

実行時、型エラーのある項を評価する必要が発生すると、そのエラーは実行時例外へと変換される。実行中、型エラーは可能な限り遅らされるが、不正な型変換(coercion)は決して実行されないことに注意。これは、最終的に正しい型を持つ値を生成するような場合でも同様である。例として、以下のコードが与えられたとする。

x :: Int
x = 0

y :: Char
y = x

z :: Int
z = y

zを評価すると、実行時型エラーが発生する。

7.15.2. GHCiで型エラーを遅らせる

-fdefer-type-errorsフラグはGHCiでも動作するが、例外が一つある。プロンプトに入力された「裸の」式については、型エラーは遅らせられない。よって、例えば

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のような単純な型エラーのある式をプロンプトに入力したようなよくある場合に、警告がまず表示され、次にすぐさま式が評価されて型エラーが表示されることになる。

この例外は文には適用されない。以下の例がこれを実演する。

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