[Haskell-cafe] ScopedTypeVariables in let-bindings (not where-bindings!) and bug 4347

Paolo G. Giarrusso p.giarrusso at gmail.com
Sat May 21 16:17:53 CEST 2011

On May 21, 3:18 pm, Felipe Almeida Lessa <felipe.le... at gmail.com>
> I have no problems in defining those functions:
> $ ghci
> GHCi, version 6.12.3:http://www.haskell.org/ghc/ :? for help
> Loading package ghc-prim ... linking ... done.
> Loading package integer-gmp ... linking ... done.
> Loading package base ... linking ... done.
> Loading package ffi-1.0 ... linking ... done.
> Prelude> let id2 :: t -> t; id2 = \x -> x
> Prelude> let a :: a -> a; a = a a
> Note that I used ';'.  This is equivalent to writing
>   let a :: a -> a
>       a = a a

First, thanks to you and everybody for the alternative. But I'm still
convinced that the syntax is supposed to work, and you're just
workarounding the bug.

> If I try the syntax you were trying without ScopedTypeVariables, I get
> Prelude> let a :: a -> a = a a
> <interactive>:1:4:
>     Illegal signature in pattern: a -> a
>         Use -XScopedTypeVariables to permit it
> GHCi thinks that you were trying to define a function by pattern
> matches and there was a signature inside it, which is a different
> thing.
As I said, I'm convinced that the argument of let is a pattern, on
which a signature is allowed, and GHC correctly understands that, so
that this declaration work:
let (id :: Int -> Int) = \x -> x

See both of:
> This is the expected use for such thing:

> Prelude> :s -XScopedTypeVariables
> Prelude> let id2 :: forall t. t -> t; id2 (x :: t) = x

Why does then the following declaration work?
let (id :: Int -> Int) = \x -> x
To me, this inconsistent behavior is a bug, and surely it is
undesirable, because of inconsistency - the programmer needs to have
sensible rules, about when let var : type = expr works and when not.
Or at least a sensible error message.

Moreover, the proposed solution not always works.
Neither of these work:
let f :: x -> x; g :: y -> y; (f, g) = (id, id)
let f :: x -> x; g :: y -> y; (f, g) = (f, g)

let (f :: forall a. a -> a, g :: forall a. a -> a) = (f, g)
let (f :: forall a. a -> a, g :: forall a. a -> a) = (id, id)

If you wonder why one , the tuple might be returned by another

Additionally, I'd like to debug documentation. If, when looking up
docs, I can't find a solution, either I miss something or the
documentation is incomplete. In the second case, I'd like to propose

I've just verified that the Haskell Report allows the syntax you
describe, but of course it doesn't specify the behavior of the
extension. But for instance I've not found type declaration for let
bindings in Real World Haskell (a Gentle introduction to Haskell
mentions them in one point of the document, without examples).


Paolo G. Giarrusso

More information about the Haskell-Cafe mailing list