GADT record syntax and contexts

Dear GHCers, Maybe this question is more for Haskell-cafe, but since it involves language extensions as provided by GHC, it seems reasonable to post it here. The GHC user guide lists under 7.4 [1] the extensions to data types and type synonyms. My question involves 7.4.5 (although the overlap with 7.4.6 is considerable; maybe the two should be merged). A property of GADTs that I really appreciate is the fact that constructor contexts are made available by pattern matching (I don't quite understand why normal ADTs could do this, btw, but that's another question). The problem I have now, though, is that there doesn't seem to be a syntax to combine contexts and records in GADTs. Consider this program: data ContTest a where A :: Show a => a -> ContTest a data RecTest a where B { arg :: a } :: RecTest a data RecContTest a where C { showable :: Show a => a } :: RecContTest a a :: ContTest a -> String a (A a) = show a b :: Show a => RecTest a -> String b = show . arg c :: RecContTest a -> String c (C { showable = x }) = show x Both ContTest and RecTest work swimmingly (with functions a and b, respectively). However, GHC complains that it can not deduce Show for type a in function c. My definition of RecContTest is the only syntactical form I could come up with that GHC accepts. Is there a syntax for what I want here? Regards, Philip PS. As a side-note. In section 7.4.5, the manual states that: "At the moment, record updates are not yet possible with GADT-style declarations, so support is limited to record construction, selection and pattern matching." However, if I add: update org@(B {}) x = org { arg = x } and evaluate "b $ update (B True) False" the response is "False" as one would expect. Is this line in the user guide outdated, or is support for updates unstable or partial? [1]http://www.haskell.org/ghc/docs/latest/html/users_guide/data-type-extensions...

Philip Thanks for your msg (which appears in full below for reference.) | data RecContTest a where | C { showable :: Show a => a } :: RecContTest a This definitely isn't going to work: it declares the 'showable' field to be a function that *requires* a Show context, not one that *provides* a Show context. | type a in function c. My definition of RecContTest is the only | syntactical form I could come up with that GHC accepts. Is there a | syntax for what I want here? Not at the moment, I'm afraid. The problem is mainly to find a decent syntax -- and that problem made me simply omit it altogether. Probably the most plausible possibilities are (A) data RecContTest a where Show a => C { showable :: Show a => a } :: RecContTest a (B) data RecContTest a where C :: Show a => { showable :: Show a => a } -> RecContTest a The latter (B) looks best to me. I dislike (A) because part of the type (the "Show a =>") occurs before the constructor name C, and part appears after. On the other hand, (B) has something that looks vaguely like a type { x::ty, y::ty } -> ty but that's not really valid type syntax. (Mind you, the ! marks in a constructor signature aren't part of valid types either, so maybe it's not so bad to have a special form in constructor declarations.) But if we were going to adopt (B), then even when there is no class context we should really say (B) data RecTest a where B :: { arg :: a } -> RecTest a rather than the current syntax which is (A) data RecTest a where B { arg :: a } :: RecTest a [Note the different placement of the double colon and arrow in (B).] My take on this (B) looks nicer, but it would represent a breaking change But perhaps not many people use record-style syntax + GADT-style syntax And better to make breaking changes sooner than later Question for everyone: * are (A) and (B) the only choices? * do you agree (B) is best Simon | -----Original Message----- | From: glasgow-haskell-users-bounces@haskell.org [mailto:glasgow-haskell-users- | bounces@haskell.org] On Behalf Of Philip K.F. Hölzenspies | Sent: 15 June 2009 11:09 | To: glasgow-haskell-users@haskell.org | Subject: GADT record syntax and contexts | | Dear GHCers, | | Maybe this question is more for Haskell-cafe, but since it involves | language extensions as provided by GHC, it seems reasonable to post it | here. | | The GHC user guide lists under 7.4 [1] the extensions to data types and | type synonyms. My question involves 7.4.5 (although the overlap with | 7.4.6 is considerable; maybe the two should be merged). A property of | GADTs that I really appreciate is the fact that constructor contexts are | made available by pattern matching (I don't quite understand why normal | ADTs could do this, btw, but that's another question). The problem I | have now, though, is that there doesn't seem to be a syntax to combine | contexts and records in GADTs. Consider this program: | | data ContTest a where | A :: Show a => a -> ContTest a | | data RecTest a where | B { arg :: a } :: RecTest a | | data RecContTest a where | C { showable :: Show a => a } :: RecContTest a | | a :: ContTest a -> String | a (A a) = show a | | b :: Show a => RecTest a -> String | b = show . arg | | c :: RecContTest a -> String | c (C { showable = x }) = show x | | Both ContTest and RecTest work swimmingly (with functions a and b, | respectively). However, GHC complains that it can not deduce Show for | type a in function c. My definition of RecContTest is the only | syntactical form I could come up with that GHC accepts. Is there a | syntax for what I want here? | | Regards, | Philip | | | | PS. As a side-note. In section 7.4.5, the manual states that: | | "At the moment, record updates are not yet possible with GADT-style | declarations, so support is limited to record construction, selection | and pattern matching." | | However, if I add: | | update org@(B {}) x = org { arg = x } | | and evaluate "b $ update (B True) False" the response is "False" as one | would expect. Is this line in the user guide outdated, or is support for | updates unstable or partial? | | | [1]http://www.haskell.org/ghc/docs/latest/html/users_guide/data-type-extensions...

Simon Peyton-Jones wrote:
(A) data RecContTest a where Show a => C { showable :: Show a => a } :: RecContTest a
(B) data RecContTest a where C :: Show a => { showable :: Show a => a } -> RecContTest a
What about (A') data RecContTest a where Show a => C { showable :: a } :: RecContTest a (B') data RecContTest a where C :: Show a => { showable :: a } -> RecContTest a ? Would this be allowed? I would expect A' and B' to generate showable :: RecContTest a -> a and not the less useful (Show-requiring) showable :: Show a => RecContTest a -> a Zun.

Dear Simon and fellow GHCers, Thank you for having a look at this. I've inlined my response with your message.
| data RecContTest a where | C { showable :: Show a => a } :: RecContTest a
This definitely isn't going to work: it declares the 'showable' field to be a function that *requires* a Show context, not one that *provides* a Show context.
Absolutely. Like I said, I committed the sin of hacking until GHC stopped complaining. At some point, I turned off the semantics in my head ;)
The problem is mainly to find a decent syntax -- and that problem made me simply omit it altogether. Probably the most plausible possibilities are
(A) data RecContTest a where Show a => C { showable :: Show a => a } :: RecContTest a
(B) data RecContTest a where C :: Show a => { showable :: Show a => a } -> RecContTest a
I presume there's a little copy-paste mishap going on here and that you mean: (A) data RecContTest a where Show a => C { showable :: a } :: RecContTest a (B) data RecContTest a where C :: Show a => { showable :: a } -> RecContTest a
The latter (B) looks best to me. I dislike (A) because part of the type (the "Show a =>") occurs before the constructor name C, and part appears after. On the other hand, (B) has something that looks vaguely like a type { x::ty, y::ty } -> ty but that's not really valid type syntax. (Mind you, the ! marks in a constructor signature aren't part of valid types either, so maybe it's not so bad to have a special form in constructor declarations.)
I'm afraid I'm not too well informed with regards to type syntax, but another reason to prefer B over A is that it looks much more like a normal function declaration. When I explain GADTs and their syntax to people that haven't used them before, I usually start off by saying that constructors are simply functions. With GADTs, the declarations of the constructors look exactly like those of functions, but you don't have to worry about providing a binding.
But if we were going to adopt (B), then even when there is no class context we should really say
(B) data RecTest a where B :: { arg :: a } -> RecTest a
rather than the current syntax which is
(A) data RecTest a where B { arg :: a } :: RecTest a
[Note the different placement of the double colon and arrow in (B).]
Again, B is much more in-sync with "normal GADTs" (i.e. non-record syntax) and with the perspective of constructors-as-functions I mentioned above. The record parts of B don't seem to be function-like, but it is how I would define functions on extensible records (regardless of the current status of different implementations / alternatives). To me, this foo :: { bar :: Bool, tutu :: Int } -> String means that foo is a function on any record that contains at least the fields bar and tutu of the mentioned types.
My take on this (B) looks nicer, but it would represent a breaking change But perhaps not many people use record-style syntax + GADT-style syntax And better to make breaking changes sooner than later
One very important reason for me to use GADTs nowadays, is that they provide contexts in pattern matches. If normal ADTs were to do the same, I would use far less GADTs. Record syntax just makes sense when you stick more than three arguments in a constructor. Having said that, *every* ADT seems to be a record in GHC: data FooBar = Foo Int Int | Bar Char isFoo Foo {} = True isFoo _ = False Rounding up; B has my strong preference over A. I don't know whether very strong alternatives will present themselves, but B seems quite nice in general. Regards, Philip

Philip Hölzenspies wrote:
(A) data RecContTest a where Show a => C { showable :: a } :: RecContTest a
(B) data RecContTest a where C :: Show a => { showable :: a } -> RecContTest a
I like (B) better too, for any GADT record syntax... its meaning seems less confusing to me than the current(?) (A) syntax. -Isaac

On Jun 16, 2009, at 05:19 , Simon Peyton-Jones wrote:
(B) data RecTest a where B :: { arg :: a } -> RecTest a
For what it's worth (considering that I have yet to actually use GADTs), (A) looks wrong to me because there is type information before the actual type. (B) looks kinda strange as well, but the "missing" tycon seems to make more sense given that it's a GADT. -- brandon s. allbery [solaris,freebsd,perl,pugs,haskell] allbery@kf8nh.com system administrator [openafs,heimdal,too many hats] allbery@ece.cmu.edu electrical and computer engineering, carnegie mellon university KF8NH

| PS. As a side-note. In section 7.4.5, the manual states that: | | "At the moment, record updates are not yet possible with GADT-style | declarations, so support is limited to record construction, selection | and pattern matching." | | However, if I add: | | update org@(B {}) x = org { arg = x } | | and evaluate "b $ update (B True) False" the response is "False" as one | would expect. Is this line in the user guide outdated, or is support for | updates unstable or partial? Ah yes. The support is partial. The update is supported if it "makes sense" from a type point of view. I should write down what "makes sense" means! Simon
participants (6)
-
Brandon S. Allbery KF8NH
-
Isaac Dupree
-
Philip Hölzenspies
-
Philip K.F. Hölzenspies
-
Roberto Zunino
-
Simon Peyton-Jones