7.14. 型付き穴

型付き穴への対応は-fwarn-typed-holesによって有効になる。このオプションはデフォルトで有効である。

このオプションを使うと、アンダースコアから始まる特殊なプレースホルダ(たとえば、"_"、"_foo"、"_bar")が、式として許される。これらの穴は、コンパイルに際して、そこにどの型が求められるか、自由な型変数があればそれの出所に関する情報、穴を実際のコードで埋める際に使えるかもしれない局所変数の一覧、をそれぞれ記したエラーメッセージを生成する。

型付き穴の目的は、型システムを変えることではなく、Haskellコードを書くのを助けることである。型付き穴は、型検査器が持っている追加の情報を得るために使うことができる。これらの情報は、通常では得難いこともある。通常、ユーザは、GHCiを使って、最上位の束縛の(推論された)型シグネチャを確認することができる。しかし、この方法は、最上位では意味を為さない項や、複雑な式に適用するのには不便である。穴を使うことによって、あなたがこれから書く項の型を確かめることができる。

穴は、型エラーを実行時まで遅延することと相性が良い。-fdefer-type-errorsが有効だと、穴に由来するエラーも遅延され、実質的に穴がundefinedであるかのように型検査されることになるが、これに加えて、評価された際にはその警告メッセージが表示されるという利点がある。この方法を使うと、プログラムの他の場所を実行したりテストしたりすることが問題なくできる。

例えば、以下のモジュールをGHCでコンパイルする。

f :: a -> a
f x = _

これは以下のエラーメッセージを出力して失敗する。

hole.hs:2:7:
    Found hole `_' with type: a
    Where: `a' is a rigid type variable bound by
               the type signature for f :: a -> a at hole.hs:1:6
    Relevant bindings include
      f :: a -> a (bound at hole.hs:2:1)
      x :: a (bound at hole.hs:2:3)
    In the expression: _
    In an equation for `f': f x = _

複数の型付き穴を使うことで、式の間で共有されている型変数を見付けることができる。例を挙げる。

sum :: [Int] -> Int
sum xs = foldr _f _z xs

これは以下を表示する。

holes.hs:2:15:
    Found hole `_f' with type: Int -> Int -> Int
    In the first argument of `foldr', namely `_'
    In the expression: foldr _a _b _c
    In an equation for `sum': sum x = foldr _a _b _c

holes.hs:2:17:
    Found hole `_z' with type: Int
    In the second argument of `foldr', namely `_'
    In the expression: foldr _a _b _c
    In an equation for `sum': sum x = foldr _a _b _c

束縛されていない同名の識別子が複数ある場合、一つの関数の中であっても、まとめられずに個別の表示される。例を挙げる。

cons = _x : _x

これは以下のエラーを生成する。

unbound.hs:1:8:
    Found hole '_x' with type: a
    Where: `a' is a rigid type variable bound by
               the inferred type of cons :: [a] at unbound.hs:1:1
    Relevant bindings include cons :: [a] (bound at unbound.hs:1:1)
    In the first argument of `(:)', namely `_x'
    In the expression: _x : _x
    In an equation for `cons': cons = _x : _x

unbound.hs:1:13:
    Found hole '_x' with type: [a]
    Arising from: an undeclared identifier `_x' at unbound.hs:1:13-14
    Where: `a' is a rigid type variable bound by
               the inferred type of cons :: [a] at unbound.hs:1:1
    Relevant bindings include cons :: [a] (bound at unbound.hs:1:1)
    In the second argument of `(:)', namely `_x'
    In the expression: _x : _x
    In an equation for `cons': cons = _x : _x

これによって、未束縛の識別子が、型が単一化できないような形で複数回使われた場合に、forall a. aのような多相的すぎる型が報告されることを防いでいる。