clay icon indicating copy to clipboard operation
clay copied to clipboard

RFC: Replace tuples with record literals

Open ghost opened this issue 12 years ago • 9 comments

record Tuple[..T] ( ..x:T );

[..T]
overload Tuple(..x:T) = Tuple[..T](..x);


foo( x:Tuple[..T] ) {...}   // Matches named record

bar( x:[..T] ) {...}        // Matches anonymous record

var myrec = Tuple(3, 5);
var myrec2 = [3, 5];        //This is an anonymous record with single variadic field

foo(myrec);  // valid
foo(myrec2); // invalid
bar(myrec);  // invalid
bar(myrec2); // valid

// Use keyword arguments to construct named fields

var a = [3, 5];             // Allowed -> unnamedRecord[..T](..data:T);
var b = [x = 3, y = 5];     // Allowed -> unnamedRecord(x:Int, y:Int);
var c = [x = 3, 5];         // Allowed -> unnamedRecord[..T](x:Int, ..data:T);
var d = [3, x = 5, 6]       // Not allowed as cannot split variadic field

goo( rec:[x:Int, ..T] ) { } // Unification matches field names so ...

goo(c);     // valid
goo(b);     // invalid

Could also allow anonymous record type specs to match named records if fields match e.g. from the above example bar(myrec) would be valid.

ghost avatar Nov 19 '12 18:11 ghost

Sounds good to me; I always thought having variadic fields in records would be preferable to having builtin Tuple[..T] as a workaround. Keyword arguments in tuple/record constructors would be great too. One potential wrench in the works is that tuples are used for a bunch of builtin features, like recordWithProperties and function types. With keyword arguments, you could potentially support multiple variadic arguments to a function:

foo(..x, ..y) { ... }

bar() { foo(x = (1,2,3), y = (4, 5, 6)); }

Function type inputs and outputs could then be handled as keywords without tuples, such as CodePointer[inputs=(A, B), outputs=C], although that's getting pretty verbose.

jckarter avatar Nov 19 '12 18:11 jckarter

Also, on a related note, how about adopting type definitions similar to those in Koka?

type MyType (); // Empty record

type Foo ( [a:Int32, b:MyType] ); // Effectively a record (brackets could be dropped here ...)

type Maybe [T] ( Nothing, T );   // Effectively a variant with Nothing as empty type

type Bar [T, ..U] (
    Foo,
    MyType,
    Cabbage(x:Maybe[T], ..y:U),  // New record-like type defined as part of variant-like type
);

A few constraints would be needed on the use of anonymous record literals etc.

(Hmm, probably should have put this one in #401)

ghost avatar Jan 15 '13 15:01 ghost

Looks cool for me. Functional ADT syntax is totally reinvented. Comma in variants could be "|" to make it more consistent with constructor.

type MyType (); // constructed by MyType();
type Foo (a:Int32, b:MyType); //constructed by Foo(a, b);
type Maybe [T] ( Nothing | T ); //constucted by Maybe[Int](5);

Round brackets can be removed at all, but I don't like this because we have brackets in function calls. f(1,2), not f 1,2 ergo F[T](t:T). Otherwise haskell will be reinvented.

galchinsky avatar Jan 16 '13 23:01 galchinsky

I meant just remove the square brackets for that special case, not all parentheses.

ghost avatar Jan 17 '13 01:01 ghost

Remove square brackets? What is the difference between record and variant in this case?

galchinsky avatar Jan 17 '13 07:01 galchinsky

I guess the idea is to unify type declarations so record and variant (and enum?) would just be special cases of type.

Checkout Koka types.

ghost avatar Jan 17 '13 12:01 ghost

The idea is clear, this unification is done in almost every language with algebraic datatypes, not only Koka. I asked about another thing. Koka uses the rule "record fields are separated by comma, variant instances are separated by space". I suggest the rule with comma and pipe symbol. In your case I dont see the difference between Maybe (variant) and Foo (record) if brackets are removed. The both are comma-separated

galchinsky avatar Jan 17 '13 13:01 galchinsky

I suppose the difference is the same as that for static and non-static function arguments except that they cannot be mixed. This works as records cannot have static fields.

e.g.

type Foo ( Bar ); // Variant type as Bar is record
type Foo [T] ( Bar(a:T) ); // Variant with Bar record as member
type Maybe[T] ( Nothing, a:T ); // Illegal as 'a:T' is field

ghost avatar Jan 17 '13 13:01 ghost

Variant instances don't have names, record fiels have... This works but looks too cryptic to me

galchinsky avatar Jan 17 '13 13:01 galchinsky