4

次の悪いコードを検討してください:

fun x = 
    if (null x) then 0
    else (take 50 x) : (fun (drop 50 x)) 

問題なくghciにロードできることに気づきました。それが問題です。
この関数を評価しようとすると、プログラムはエラーを取得するだけです。

if ... then ... else 式のデフォルトの推論規則に関して、2 つの分岐が明示的に異なる型を取得するため、このコードをロード (コンパイル) できるのはなぜですか? つまり、なぜコンパイラはこのコードが不正であると判断できないのでしょうか?

注:もちろん、この関数に正しい型注釈を追加すると、予想どおり拒否されますが、私の理解では、型注釈なしでも拒否する必要があります。

4

2 に答える 2

16

オーバーロードされた数値リテラル。Haskell 数値リテラルは、型コンテキストに基づいて定義された Num クラスのインスタンスです。

推論されたタイプはそれを説明します:

Prelude> let f x = if null x then 0 else take 50 x : f (drop 50 x)

Prelude> :t f
f :: Num [[a]] => [a] -> [[a]]

これは、「 のリストのリストの Num クラスのインスタンスがある場合、aこの関数は a のリストから a のリストのリストを取得します。

したがって、リストのリストについては Num の神話上のインスタンスに依存しています。リストのリストに数値のインスタンスを提供せずに、これを使用するコードをコンパイルしようとすると、コンパイル エラーになります。

この例は、型シグネチャを最初に書き留めておくことがなぜ良い考えなのかを示しています。

于 2013-03-02T17:47:29.653 に答える
3

これをチェックしてみましょう。

Prelude> let fun x = if (null x) then 0 else (take 50 x) : (fun (drop 50 x)) 
Prelude> :t fun
fun :: Num [[a]] => [a] -> [[a]]

ご覧のとおり、コンパイラはNum結果の型のクラスを推測します。

于 2013-03-02T17:47:19.357 に答える