[GHC] #15674: GADT's displayed type is misleading
GHC
ghc-devs at haskell.org
Sat Sep 29 21:05:16 UTC 2018
#15674: GADT's displayed type is misleading
-------------------------------------+-------------------------------------
Reporter: AntC | Owner: (none)
Type: feature request | Status: new
Priority: normal | Milestone: 8.6.1
Component: Compiler | Version: 8.6.1-beta1
Resolution: | Keywords:
Operating System: Windows | Architecture: x86_64
Type of failure: Poor/confusing | (amd64)
error message | Test Case:
Blocked By: | Blocking:
Related Tickets: | Differential Rev(s):
Wiki Page: |
-------------------------------------+-------------------------------------
Comment (by goldfire):
Replying to [comment:5 AntC]:
> > There is no `forall` in `MkDG`, which doesn't quantify over any
variables.
> >
>
> Then I totally ignore the `a` in the `data DG a where ...`?
In GADT syntax, the bit between the `data` and the `where` is the
declaration for the type only -- not any constructors. The `a` there
serves to say that `DG` takes one argument. It does not affect or cause
any variable quantification in constructors.
>
> For `MkDG2`, with `-fprint-explicit-foralls`
> `:i` shows `MkDG2 :: forall a. (a ~ Int) => a -> DG a`
>
> `:t` shows `MkDG2 :: Int -> DG Int`
>
> With `-fno-print-explicit-foralls`
> `:i` shows `MkDG2 :: (a ~ Int) => a -> DG a`
>
> `:t` shows `MkDG2 :: Int -> DG Int`
>
> Is that intended behaviour? It doesn't seem either internally
consistent, nor consistent with your explanation: why is the `forall`
appearing at all? Why is it appearing for `:i` but not `:t`?
Yes, this is all expected behavior. Haskell allows you omit `forall`s if
you have a type variable in a type. But when you write `-fprint-explicit-
foralls`, it will print one even if you left it out. So: the `forall`
appears because you asked for it.
I'll quote myself:
> `:type <expr>` gives you the type that is assigned to it if you had `let
it = <expr>`. It's a uniform rule that always works.
When we say `let it = MkDG2`, GHC instantiates the type of `MkDG2` at its
occurrence and then generalizes (because `let`-bound variables are
generalized). Thus, `it` might not have exactly the same type as `MkDG2`,
which is what's happening here.
Here's a simpler example:
{{{#!hs
silly :: (Ord a, Eq a) => a -> Bool
silly = ...
}}}
Asking for `:t silly` gives you `Ord a => a -> Bool`. This is because we
instantiate and regeneralize the type of `silly`. In this process, GHC
realizes that `Eq a` is redundant and drops it. The same is happening with
`MkDG2`.
> What I'm looking for with these mind-blowingly similar-but- "subtly
different" nuances is strong help from the compiler to navigate error
messages when I get my types wrong.
Short of a use of a type application (which doesn't seem to be what you're
doing), `MkDG` and `MkDG2` behave identically.
--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/15674#comment:7>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
More information about the ghc-tickets
mailing list