Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>First, let's clarify one thing. What happens if we define the function in GHCi, rather than querying the type?</p> <pre><code>&gt; let x = map length . sum :: (Num [[a]]) =&gt; [[[a]]] -&gt; [Int] &lt;interactive&gt;:0:9: Non type-variable argument in the constraint: Num [[a]] (Use -XFlexibleContexts to permit this) In an expression type signature: Num [[a]] =&gt; [[[a]]] -&gt; [Int] </code></pre> <p>And so on. In other words, the same thing. What if we let GHCi infer the type of the definition?</p> <pre><code>&gt; let x = map length . sum &lt;interactive&gt;: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 </code></pre> <p>This is roughly the same error that results from loading a file containing the definition without a type signature.</p> <p>What's the upshot of all this? Well, think about the fact that it <em>tells</em> you what extension is needed. GHC is capable of recognizing what the type <em>means</em>, even if it rejects the type by default. I'd hardly expect GHC to use a completely different type checker depending on the combination of extensions used, so it seems easy to conclude that the offending type is being rejected for no reason other than the relevant extension being disabled.</p> <p>The <code>:t</code> command in GHCi isn't part of the compilation process--it's a hotline to the type checking and inference system, letting you ask the type of hypothetical code. There's no obvious reason for it to restrict itself arbitrarily based on extensions, when a more general type could still be informative, for the same reason that the error messages above tell you <code>use -XFlexibleContexts to permit this</code> rather than merely <code>syntax error in type constraint</code>.</p> <hr> <p>As a possibly more interesting aside, there are also cases where an inferred type will be accepted happily by the compiler, but the inferred type can't actually be written out explicitly for one of several reasons.</p> <p>For instance, disabling the monomorphism restriction will allow your example to have its type inferred (matching what <code>:t</code> says), despite that type requiring an extension to write manually.</p> <p>Another example are definitions in the <code>where</code> clause of a function definition which make use of polymorphic arguments to the parent function. Their own types are not polymorphic, being dictated by the arguments received in the outer scope, yet the type variables in the parent function's signature are not in scope for the <code>where</code> clause¹. There may be other examples as well.</p> <p>¹ The type variables from the parent's signature can be brought into scope with the <code>ScopedTypeVariables</code> extension and an explicit <code>forall</code>, if that's needed.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload