
On 12/11/2010, at 6:06 PM, Sebastian Fischer wrote:
As others have pointed out, type classes are insufficient for overloading record labels because they do not cover record updates.
How can we add a special kind of overloading for record labels that also works for updates? Maybe like this:
rename :: ((name :: String) @ a) => a -> a rename newName someRecord = someRecord { name = newName }
Why is nobody talking about records in Clean? Clean is a Haskell-like language, indeed, the latest feature in Clean is an additional front-end so it can compile Haskell directly. Adapting section 5.2 from the Clean 2.1 language specification: A record type is ... an algebraic data type [with] exactly one constructor. ... a field name is attached to each of [its] arguments. Records cannot be used in a curried way. ... selection [is] by field name. When a record is created all arguments of the constructor have to be [provided] but ... in any order. ... When pattern matching ... on a record, one [need only] mention those fields one is interested in. A record can be created via a functional update [where] one [need only] specify the values for this fields that differ from the old record. RecordTypeDef = '::' TypeLhs '=' [UniversalQuantVariables] '{' (FieldName '::' [Strict] Type)-list '}' ... The semantic restrictions [of] algebraic data types also hold for record types. The field names inside one record all have to be different. It is allowed to use the same field name in different records. Record = RecordDenotation | RecordUpdate RecordDenotation = '{' [TypeName '|'] (FieldName '=' Expr)-list '}' A record can only be used if its type has been defined ... the field names must be identical to the field names ... in the corresponding type. ... The order in which the record fields are instantiated is irrelevant, but all fields have to get a value [of the right type]. ... When creating a record, its type [name] can be used to disambiguate [the type]; the type constructor can be left out if there is at least one field name [that is peculiar to the type]. There's a little gotcha there: ::T1 = {x :: Int, y :: Int} ::T2 = {y :: Int, z :: Int} ::T3 = {z :: Int, x :: Int} {x = 1, y = 2} neither x by itself nor y by itself uniquely determines a record type, so Clean 2.1 wanted {T1 | x = 1, y = 2} here. I don't happen to have a copy of the current manual handy, so I don't know if they've fixed this yet. RecordUpdate = '{' [TypeName '|'] [RecordExpr '&'] [(FieldName Selection... '=' Expr)-list] '}' Selection = '.' FieldName | '.' '[' Expr-list ']' The record written to the left of the '&' ... is the record to be updated. On the right [of] the '&' are specified the structures in which the new record differs from the old one. A structure an be any field of the record or a selection of any field or array elements of a record or array stored in this record. Notice that the functional update is not an update in the classical, destructive, sense since a new record is created. The functional update of records is performed very efficient[ly] [so] that we have not added support for destructive updates of records of unique type. The '&' operator is strict in its arguments. RecordSelection = RecordExpr ['.'TypeName] '.'FieldName Selection... | RecordExpr ['.'TypeName] '!'FieldName Selection... The "!" alternative has to do with Clean's uniqueness typing. An object of [a record] type ... can be specified as [a] pattern. Only those fields [whose] contents one would like to use [on] the right hand side need to be mentioned in the pattern. RecordPattern = '{' [TypeName '|'] (FieldName ['=' Pattern])-list '}' The type of the record must have been defined ... . The field names in the pattern must be identical to the field names [in that definition]. ... The [TypeName] can only be left out if there is at least one field name [which is not defined in any other record type]. See the T1, T2, T3 example above; I repeat that I haven't checked the latest manual and don't know if the obvious fix has been made yet. By the way, Clean can freely use '.' for selection because it uses 'o' for function composition. I remind readers once again that the latest Clean release compiles Haskell as well as Clean, so there is a sense in which records like this *are* available to some Haskell programmers. Do they meet the needs that people have been expressing here? There's no subtyping, but then, I have reasons for not using CAML. The only reason I don't use Clean is that I can't. Clean's original home was MacOS, but they moved to Windows. The latest stable release for the Mac is 32-bit only, PowerPC only, and 4 years old. Solaris has been abandoned completely. Only Windows is seeing any active support. This has nothing to do with records. Since Clean's type system is so very like the Haskell98 type system (except that their prelude breaks the numeric type classes down to the level of single operations, so that there is a + class and a * class and so on), this record system would seem to be pretty much compatible with Haskell.