From nikita.y.volkov at gmail.com Mon Oct 14 16:13:43 2013 From: nikita.y.volkov at gmail.com (Nikita Volkov) Date: Mon, 14 Oct 2013 20:13:43 +0400 Subject: Anonymous records. A solution to the problems of record-system. Message-ID: Anonymous records. A solution to the problems of record-system. The current record system is notorious for three major flaws: 1. It does not solve the namespacing problem. I.e., you cannot have two records sharing field names in a single module. E.g., the following won't compile: data A = A { field :: String }data B = B { field :: String } 2. It's partial. The following code will result in a runtime error: data A = A1 { field1 :: String } | A2 { field2 :: String } main = print $ field1 $ A2 "abc" 3. It does not allow you to use the same field name for different types across constructors: data A = A1 { field :: String } | A2 { field :: Int } This proposal approaches all the problems above and also a fourth one, which is unrelated to the current record system: it allows one to avoid declaration of intermediate types (see details below). Gentlemen, I want you to meet, <#anonymous-records>Anonymous Records When a record-syntax is used in Haskell it's almost always a single-constructor ADT. A question rises then: why use ADT when you don't need its main feature (i.e., the multiple constructors)? This main feature is actually the root of the second and the third problem of record-syntax from the list above. In such situations one doesn't actually need ADT, but something more like a tuple with ability to access its items by name. E.g.: f :: (a :: Int, b :: String) -> Stringf rec = rec.b ++ show rec.a application: f (a = 123, b = "abc") So now you think "Okay, but how about naming it?". Well, not a problem at all - use the existingtype-construct: type TheRecord = (a :: Int, b :: String) Now, about the avoidance of intermediate types: type Person = (name :: String, phone :: (country :: Int, area :: Int, number :: Int)) See? No need to declare separate types for inner values. But, of course, if you need, you still can: type Phone = (country :: Int, area :: Int, number :: Int)type Person = (name :: String, phone :: Phone) We can nicely access the deeply nested fields, e.g.: personCountryCode :: Person -> IntpersonCountryCode person = person.phone.country Okay. What about the type ambiguity? E.g., in the following the Person is actually the same type asCompany: type Person = (name :: String, phone :: Phone)type Company = (name :: String, phone :: Phone) Easily solvable with a help of newtype: newtype Person = Person (name :: String, phone :: Phone)newtype Company = Company (name :: String, phone :: Phone) What about ADTs? Again, easy: data Product = Tea (brand :: Company) | Milk (brand :: Company, fatness :: Float) Now, the beautiful fact: This solution does not conflict with any existing feature of Haskell! As the examples show, it easily fits into the language as an extension. It can peacefully coexist with the existing record system of ADTs. Hence a complete backwards compatibility with old codebase. There's also a potential for many other additional features. <#links>Links - Source of this proposal . -------------- next part -------------- An HTML attachment was scrubbed... URL: From chrisdone at gmail.com Mon Oct 14 16:17:50 2013 From: chrisdone at gmail.com (Christopher Done) Date: Mon, 14 Oct 2013 18:17:50 +0200 Subject: Anonymous records. A solution to the problems of record-system. In-Reply-To: References: Message-ID: So basically, TRex? On 14 October 2013 18:13, Nikita Volkov wrote: > Anonymous records. A solution to the problems of record-system. > > The current record system is notorious for three major flaws: > > It does not solve the namespacing problem. I.e., you cannot have two records > sharing field names in a single module. E.g., the following won't compile: > > data A = A { field :: String } > data B = B { field :: String } > > It's partial. The following code will result in a runtime error: > > data A = A1 { field1 :: String } | A2 { field2 :: String } > > main = print $ field1 $ A2 "abc" > > It does not allow you to use the same field name for different types across > constructors: > > data A = A1 { field :: String } | A2 { field :: Int } > > This proposal approaches all the problems above and also a fourth one, which > is unrelated to the current record system: it allows one to avoid > declaration of intermediate types (see details below). > > Gentlemen, I want you to meet, > > Anonymous Records > > When a record-syntax is used in Haskell it's almost always a > single-constructor ADT. A question rises then: why use ADT when you don't > need its main feature (i.e., the multiple constructors)? This main feature > is actually the root of the second and the third problem of record-syntax > from the list above. In such situations one doesn't actually need ADT, but > something more like a tuple with ability to access its items by name. E.g.: > > f :: (a :: Int, b :: String) -> String > f rec = rec.b ++ show rec.a > > application: > > f (a = 123, b = "abc") > > So now you think "Okay, but how about naming it?". Well, not a problem at > all - use the existingtype-construct: > > type TheRecord = (a :: Int, b :: String) > > Now, about the avoidance of intermediate types: > > type Person = (name :: String, phone :: (country :: Int, area :: Int, number > :: Int)) > > See? No need to declare separate types for inner values. But, of course, if > you need, you still can: > > type Phone = (country :: Int, area :: Int, number :: Int) > type Person = (name :: String, phone :: Phone) > > We can nicely access the deeply nested fields, e.g.: > > personCountryCode :: Person -> Int > personCountryCode person = person.phone.country > > Okay. What about the type ambiguity? E.g., in the following the Person is > actually the same type asCompany: > > type Person = (name :: String, phone :: Phone) > type Company = (name :: String, phone :: Phone) > > Easily solvable with a help of newtype: > > newtype Person = Person (name :: String, phone :: Phone) > newtype Company = Company (name :: String, phone :: Phone) > > What about ADTs? Again, easy: > > data Product = Tea (brand :: Company) > | Milk (brand :: Company, fatness :: Float) > > Now, the beautiful fact: > > This solution does not conflict with any existing feature of Haskell! As the > examples show, it easily fits into the language as an extension. It can > peacefully coexist with the existing record system of ADTs. Hence a complete > backwards compatibility with old codebase. There's also a potential for many > other additional features. > > Links > > Source of this proposal. > > > _______________________________________________ > Haskell-prime mailing list > Haskell-prime at haskell.org > http://www.haskell.org/mailman/listinfo/haskell-prime > From ramana at member.fsf.org Mon Oct 14 16:29:55 2013 From: ramana at member.fsf.org (Ramana Kumar) Date: Mon, 14 Oct 2013 17:29:55 +0100 Subject: Anonymous records. A solution to the problems of record-system. In-Reply-To: References: Message-ID: This list is not for "Gentlemen" only. It's best not to make that assumption with your language. On Mon, Oct 14, 2013 at 5:13 PM, Nikita Volkov wrote: > Anonymous records. A solution to the problems of record-system. > > The current record system is notorious for three major flaws: > > 1. > > It does not solve the namespacing problem. I.e., you cannot have two > records sharing field names in a single module. E.g., the following won't > compile: > > data A = A { field :: String }data B = B { field :: String } > > 2. > > It's partial. The following code will result in a runtime error: > > data A = A1 { field1 :: String } | A2 { field2 :: String } > main = print $ field1 $ A2 "abc" > > 3. > > It does not allow you to use the same field name for different types > across constructors: > > data A = A1 { field :: String } | A2 { field :: Int } > > > This proposal approaches all the problems above and also a fourth one, > which is unrelated to the current record system: it allows one to avoid > declaration of intermediate types (see details below). > > Gentlemen, I want you to meet, > <#141b7bed9546ffd9_anonymous-records>Anonymous Records > > When a record-syntax is used in Haskell it's almost always a > single-constructor ADT. A question rises then: why use ADT when you don't > need its main feature (i.e., the multiple constructors)? This main feature > is actually the root of the second and the third problem of record-syntax > from the list above. In such situations one doesn't actually need ADT, but > something more like a tuple with ability to access its items by name. E.g.: > > f :: (a :: Int, b :: String) -> Stringf rec = rec.b ++ show rec.a > > application: > > f (a = 123, b = "abc") > > So now you think "Okay, but how about naming it?". Well, not a problem at > all - use the existingtype-construct: > > type TheRecord = (a :: Int, b :: String) > > Now, about the avoidance of intermediate types: > > type Person = (name :: String, phone :: (country :: Int, area :: Int, number :: Int)) > > See? No need to declare separate types for inner values. But, of course, > if you need, you still can: > > type Phone = (country :: Int, area :: Int, number :: Int)type Person = (name :: String, phone :: Phone) > > We can nicely access the deeply nested fields, e.g.: > > personCountryCode :: Person -> IntpersonCountryCode person = person.phone.country > > Okay. What about the type ambiguity? E.g., in the following the Person is > actually the same type asCompany: > > type Person = (name :: String, phone :: Phone)type Company = (name :: String, phone :: Phone) > > Easily solvable with a help of newtype: > > newtype Person = Person (name :: String, phone :: Phone)newtype Company = Company (name :: String, phone :: Phone) > > What about ADTs? Again, easy: > > data Product = Tea (brand :: Company) > | Milk (brand :: Company, fatness :: Float) > > Now, the beautiful fact: > > This solution does not conflict with any existing feature of Haskell! As > the examples show, it easily fits into the language as an extension. It can > peacefully coexist with the existing record system of ADTs. Hence a > complete backwards compatibility with old codebase. There's also a > potential for many other additional features. > <#141b7bed9546ffd9_links>Links > > - Source of this proposal > . > > > _______________________________________________ > Haskell-prime mailing list > Haskell-prime at haskell.org > http://www.haskell.org/mailman/listinfo/haskell-prime > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From vitea3v at rambler.ru Mon Oct 14 18:55:39 2013 From: vitea3v at rambler.ru (Wvv) Date: Mon, 14 Oct 2013 11:55:39 -0700 (PDT) Subject: Anonymous records. A solution to the problems of record-system. In-Reply-To: References: Message-ID: <1381776939778-5738491.post@n5.nabble.com> The reform to modernize record is already going on. See for more details here: http://ghc.haskell.org/trac/ghc/wiki/Records/OverloadedRecordFields/Plan http://ghc.haskell.org/trac/ghc/wiki/Records/OverloadedRecordFields/Implementation -- View this message in context: http://haskell.1045720.n5.nabble.com/Anonymous-records-A-solution-to-the-problems-of-record-system-tp5738476p5738491.html Sent from the Haskell - Haskell-prime mailing list archive at Nabble.com. From vitea3v at rambler.ru Mon Oct 14 20:13:58 2013 From: vitea3v at rambler.ru (Wvv) Date: Mon, 14 Oct 2013 13:13:58 -0700 (PDT) Subject: Anonymous records. A solution to the problems of record-system. In-Reply-To: References: Message-ID: <1381781638132-5738498.post@n5.nabble.com> 1) This system is week. It is still impossible write type Person = (lastName::Sting, name :: String) type Image = ( name :: ByteString, sizeX :: Int, sizeY :: Int ) name :: (b ~ Stirng) => (a,b) -> b name :: (a ~ ByteString) => (a,b,c) -> a 2) you already could write name :: (String, b) -> String name (a, _) = a You even could write now : data Person = Person Sting String data Image = Image ByteString Int Int class Rec_Name a where type OutRec_Name a name :: a -> OutRec_Name a instance (OutRec_Name Person ~ String) => Rec_Name Person type OutRec_Name Person = String name (Person _ a) = a instance (OutRec_Name Image ~ ByteString) => Rec_Name Image type OutRec_Name Image = ByteString name (Person a _ _) = a -- View this message in context: http://haskell.1045720.n5.nabble.com/Anonymous-records-A-solution-to-the-problems-of-record-system-tp5738476p5738498.html Sent from the Haskell - Haskell-prime mailing list archive at Nabble.com. From nikita.y.volkov at gmail.com Mon Oct 14 20:44:26 2013 From: nikita.y.volkov at gmail.com (Nikita Volkov) Date: Tue, 15 Oct 2013 00:44:26 +0400 Subject: Anonymous records. A solution to the problems of record-system. In-Reply-To: References: Message-ID: Yes, TRex indeed looks very similar. I'm quite surprised how I managed to come up with something that much similar without knowing anything about TRex. So do you know anything about why it hasn't been yet implemented? 2013/10/14 Christopher Done > So basically, TRex? > > On 14 October 2013 18:13, Nikita Volkov wrote: > > Anonymous records. A solution to the problems of record-system. > > > > The current record system is notorious for three major flaws: > > > > It does not solve the namespacing problem. I.e., you cannot have two > records > > sharing field names in a single module. E.g., the following won't > compile: > > > > data A = A { field :: String } > > data B = B { field :: String } > > > > It's partial. The following code will result in a runtime error: > > > > data A = A1 { field1 :: String } | A2 { field2 :: String } > > > > main = print $ field1 $ A2 "abc" > > > > It does not allow you to use the same field name for different types > across > > constructors: > > > > data A = A1 { field :: String } | A2 { field :: Int } > > > > This proposal approaches all the problems above and also a fourth one, > which > > is unrelated to the current record system: it allows one to avoid > > declaration of intermediate types (see details below). > > > > Gentlemen, I want you to meet, > > > > Anonymous Records > > > > When a record-syntax is used in Haskell it's almost always a > > single-constructor ADT. A question rises then: why use ADT when you don't > > need its main feature (i.e., the multiple constructors)? This main > feature > > is actually the root of the second and the third problem of record-syntax > > from the list above. In such situations one doesn't actually need ADT, > but > > something more like a tuple with ability to access its items by name. > E.g.: > > > > f :: (a :: Int, b :: String) -> String > > f rec = rec.b ++ show rec.a > > > > application: > > > > f (a = 123, b = "abc") > > > > So now you think "Okay, but how about naming it?". Well, not a problem at > > all - use the existingtype-construct: > > > > type TheRecord = (a :: Int, b :: String) > > > > Now, about the avoidance of intermediate types: > > > > type Person = (name :: String, phone :: (country :: Int, area :: Int, > number > > :: Int)) > > > > See? No need to declare separate types for inner values. But, of course, > if > > you need, you still can: > > > > type Phone = (country :: Int, area :: Int, number :: Int) > > type Person = (name :: String, phone :: Phone) > > > > We can nicely access the deeply nested fields, e.g.: > > > > personCountryCode :: Person -> Int > > personCountryCode person = person.phone.country > > > > Okay. What about the type ambiguity? E.g., in the following the Person is > > actually the same type asCompany: > > > > type Person = (name :: String, phone :: Phone) > > type Company = (name :: String, phone :: Phone) > > > > Easily solvable with a help of newtype: > > > > newtype Person = Person (name :: String, phone :: Phone) > > newtype Company = Company (name :: String, phone :: Phone) > > > > What about ADTs? Again, easy: > > > > data Product = Tea (brand :: Company) > > | Milk (brand :: Company, fatness :: Float) > > > > Now, the beautiful fact: > > > > This solution does not conflict with any existing feature of Haskell! As > the > > examples show, it easily fits into the language as an extension. It can > > peacefully coexist with the existing record system of ADTs. Hence a > complete > > backwards compatibility with old codebase. There's also a potential for > many > > other additional features. > > > > Links > > > > Source of this proposal. > > > > > > _______________________________________________ > > Haskell-prime mailing list > > Haskell-prime at haskell.org > > http://www.haskell.org/mailman/listinfo/haskell-prime > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From anthony_clayden at clear.net.nz Mon Oct 14 20:44:15 2013 From: anthony_clayden at clear.net.nz (AntC) Date: Mon, 14 Oct 2013 20:44:15 +0000 (UTC) Subject: Anonymous records. A solution to the problems of record-system. References: Message-ID: > Ramana Kumar writes: > > This list is [not] for ... > This list _is_ for mature extensions to the language, to be considered for embedding into the formal standard [as I've been told several times]. So ... > > > On Mon, Oct 14, 2013 at 5:13 PM, Nikita Volkov wrote: > > ... > Nikita: do you have an implementation of your suggestion, or is it just a 'bright idea'? There have been many, many critiques of Haskell's current record system; and many, many proposals -- this is exactly what's blocking progress. I'm not sure you've fully characterised all the current difficulties. (For example: what is to be the principal type for your anonymous records? Are two records with the same-named fields, and at the same types, but in a different l-to-r sequence to be treated as 'equivalent'?) I don't see you comparing your suggestion to others. (As Christopher noted, it does at first sight look like TRex. Do you understand why TRex was abandoned?) There's a substantial body of recent debate and suggestions at http://ghc.haskell.org/trac/ghc/wiki/Records . This [Northern] Summer's GSoC project on OverloadedRecordFields that Wvv ref'd is just one point in the possible design space. You can trace backwards from those wiki pages to many threads of discussion. From nikita.y.volkov at gmail.com Mon Oct 14 21:01:40 2013 From: nikita.y.volkov at gmail.com (Nikita Volkov) Date: Tue, 15 Oct 2013 01:01:40 +0400 Subject: Anonymous records. A solution to the problems of record-system. In-Reply-To: <1381781638132-5738498.post@n5.nabble.com> References: <1381781638132-5738498.post@n5.nabble.com> Message-ID: > It is still impossible write > > type Person = (lastName::Sting, name :: String) > type Image = ( name :: ByteString, sizeX :: Int, sizeY :: Int ) > > name :: (b ~ Stirng) => (a,b) -> b > name :: (a ~ ByteString) => (a,b,c) -> a > I think, you misunderstood the primary part: in this proposal record fields are accessed not with functions, but more like fields in OO languages. So the problem of function sharing does not exist as such. E.g.: namesOfPersonAndImage :: Person -> Image -> String namesOfPersonAndImage person image = person.name ++ ", " ++ show image.name -------------- next part -------------- An HTML attachment was scrubbed... URL: From nikita.y.volkov at gmail.com Mon Oct 14 21:41:14 2013 From: nikita.y.volkov at gmail.com (Nikita Volkov) Date: Tue, 15 Oct 2013 01:41:14 +0400 Subject: Anonymous records. A solution to the problems of record-system. In-Reply-To: References: Message-ID: > Nikita: do you have an implementation of your suggestion, or is it just > a 'bright idea'? > Just an idea for discussion with hope to interest enough people to draw in attention and probably get to implementation or at least to come up with collectively approved proposal. > I'm not sure you've fully characterised all the current difficulties. > (For example: what is to be the principal type for your anonymous records? > Are two records with the same-named fields, and at the same types, > but in a different l-to-r sequence to be treated as 'equivalent'?) > I wanted to keep the introductory message as succinct as possible, so I eluded details like that. The types should be determined both by field names and their types, and since field names are by definition unique the order in which they appear shouldn't matter. E.g.: (a :: Int, b :: Char) is the same type as (b :: Char, a :: Int) and a different type from (z :: Char, x :: Int). > I don't see you comparing your suggestion to others. (As Christopher > noted, it does at first sight look like TRex. Do you understand why TRex > was abandoned?) > Christopher's notion was my first introduction to TRex, so I'm far from knowing much about it, but it in fact does look crazily similar to the current suggestion. From what I've read so far, it hasn't been abandoned, it just has only been implemented in Hugs. > There's a substantial body of recent debate and suggestions at > http://ghc.haskell.org/trac/ghc/wiki/Records . This [Northern] Summer's > GSoC project on OverloadedRecordFields that Wvv ref'd is just one point in > the possible design space. You can trace backwards from those wiki pages > to many threads of discussion. > Thanks! This page actually says that it only addresses namespacing and doesn't approach the first class record types problem, which this suggestion does approach. For this problem it refers to a more general page: http://ghc.haskell.org/trac/ghc/wiki/ExtensibleRecords - on which TRex is actually mentioned as having a high implementation cost. >From what I've seen OverloadedRecordFields looks very much like a workaround and it does not approach the first class record types problem. Very far from the elegance of TRex. -------------- next part -------------- An HTML attachment was scrubbed... URL: