
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?
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
On 14 October 2013 18:13, Nikita Volkov
wrote: 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@haskell.org http://www.haskell.org/mailman/listinfo/haskell-prime