まず、1つのことを明確にしましょう。型を問い合わせるのではなく、GHCi で関数を定義するとどうなるでしょうか?
> let x = map length . sum :: (Num [[a]]) => [[[a]]] -> [Int]
<interactive>:0:9:
Non type-variable argument in the constraint: Num [[a]]
(Use -XFlexibleContexts to permit this)
In an expression type signature: Num [[a]] => [[[a]]] -> [Int]
等々。つまり、同じことです。GHCi に定義の型を推測させたらどうなるでしょうか?
> let x = map length . sum
<interactive>:0:22:
No instance for (Num [[a0]])
arising from a use of `sum'
Possible fix: add an instance declaration for (Num [[a0]])
In the second argument of `(.)', namely `sum'
In the expression: map length . sum
これは、型シグネチャのない定義を含むファイルをロードした結果発生するエラーとほぼ同じです。
このすべての結果は何ですか?さて、どの拡張機能が必要かを教えてくれるという事実について考えてみてください。GHC は、デフォルトで型を拒否する場合でも、型が何を意味するかを認識することができます。GHC が使用する拡張機能の組み合わせに応じてまったく異なる型チェッカーを使用するとは考えにくいため、関連する拡張機能が無効になっている以外の理由で問題の型が拒否されていると結論付けるのは簡単に思えます。
GHCiの:t
コマンドはコンパイル プロセスの一部ではありません。これは型チェックおよび推論システムへのホットラインであり、仮想コードの型を尋ねることができます。上記のエラー メッセージuse -XFlexibleContexts to permit this
が単にsyntax error in type constraint
.
おそらくもっと興味深いのは、推論された型がコンパイラによって問題なく受け入れられる場合もありますが、いくつかの理由のいずれかにより、推論された型を実際には明示的に書き出すことができないということです。
たとえば、モノモーフィズムの制限を無効にする:t
と、手動で記述する拡張機能が必要なタイプにもかかわらず、例のタイプが推論されます (言うことと一致します)。
もう 1 つの例はwhere
、親関数への多態的な引数を使用する関数定義の節での定義です。それら自身の型はポリモーフィックではなく、外側のスコープで受け取った引数によって決定されますが、親関数のシグネチャの型変数は句のスコープ内にありませんwhere
¹。他にも例があるかもしれません。
¹ 親の署名からの型変数は、必要に応じて、ScopedTypeVariables
拡張子と明示的なを使用してスコープに入れることができforall
ます。