March 29, 2013 Re: DIP32: Uniform tuple syntax | ||||
---|---|---|---|---|
| ||||
Posted in reply to kenji hara | kenji hara: > If tup[0..1] makes closed tuple implicitly, you cannot make new flattened > tuple from other tuples. > > auto x = {1,"hi"}; > auto y = {[1,2], S(1)}; > auto tup1 = {x[], y[]}; // creates {1,"hi", [1,2], S(1)} > auto tup2 = {x, y}; // creates {{1,"hi"}, {[1,2], S(1)}} > > Under your semantics, it is impossible. I (and probably Timon) am just asking for another syntax to do that. Not to make it impossible. A clean syntax to concatenate tuples: auto tup3 = x ~ y; // creates {1,"hi", [1,2], S(1)} In general I agree we need a syntax to apply the tuple items to a function. But I think the slice syntax is the wrong syntax for it. In Python you use a star, this syntax can't be used in D: >>> def foo(x, y): pass ... >>> >>> t = (1, 2) >>> foo(*t) In the Python itertools there is also a map that performs a star too: >>> from itertools import starmap >>> pow(2, 3) 8 >>> t = (2, 3) >>> list(starmap(pow, [t])) [8] In Haskell there is more than one way to do that, like using uncurry that creates a new function: Prelude> mod 10 4 2 Prelude> let t = (10, 4) Prelude> let mod2 = uncurry mod Prelude> mod2 t 2 Prelude> uncurry mod (10, 4) 2 Bye, bearophile |
March 29, 2013 Re: DIP32: Uniform tuple syntax | ||||
---|---|---|---|---|
| ||||
Posted in reply to kenji hara | kenji hara:
> I think it will become reasonable. If you really want re-packing tuple, you
> can use {tup[0..1]}. It's quite handy.
In the end it's not too much bad (despite my first instinct is for a slice of a tuple to be a true tuple), and so far I have not found better alternatives. Let's see what other people think about that.
Bye,
bearophile
|
March 29, 2013 Re: DIP32: Uniform tuple syntax | ||||
---|---|---|---|---|
| ||||
Posted in reply to kenji hara | On 03/29/2013 05:39 PM, kenji hara wrote: > 2013/3/30 bearophile <bearophileHUGS@lycos.com > <mailto:bearophileHUGS@lycos.com>> > > kenji hara: > > > I think it will become reasonable. If you really want re-packing > tuple, you > can use {tup[0..1]}. It's quite handy. > > > This is a bad idea. It is not handy and it introduces a special > case. Explicit is better than implicit. > > > That is "explicit". In D, opened tuple (currently it's generated from > template parameters, e.g. std.typetuple.TypeTuple) and closed tuple > (currently created by structs with alias tuple_field this; e.g. > std.typecons.Tuple) are distinct. Slice operator always returns opened > tuple. Because of prior language limitations, not because it makes any sense! Current operator overloading limitations mandate that it is simply not possible to create a Phobos tuple with a sane slice operator. > If tup[0..1] makes closed tuple implicitly, you cannot make new > flattened tuple from other tuples. > > auto x = {1,"hi"}; > auto y = {[1,2], S(1)}; > auto tup1 = {x[], y[]}; // creates {1,"hi", [1,2], S(1)} > auto tup2 = {x, y}; // creates {{1,"hi"}, {[1,2], S(1)}} > > Under your semantics, it is impossible. > ... Certainly not. Creating opened tuples from closed ones is not an operation necessarily tied to slicing. Making an opened tuple should be an explicit operation on closed tuples. Slicing and opening are orthogonal operations. auto tup1 = {x.open, y.open}; // creates {1,"hi", [1,2], S(1)} auto tup2 = {x[0..2], y[]}; // creates {{1,"hi}, {[1,2], S(1)}} auto tup3 = {x[0..2].open, y[].open}; // creates {1,"hi", [1,2], S(1)} |
March 29, 2013 Re: DIP32: Uniform tuple syntax | ||||
---|---|---|---|---|
| ||||
Posted in reply to kenji hara | On 03/29/2013 09:57 AM, kenji hara wrote:
> http://wiki.dlang.org/DIP32
>
> Kenji Hara
One quite ugly thing about this is that function arguments will be a distinct, incompatible and underpowered form of packing together and unpacking multiple values.
auto foo(int a, int b){ } // unpacking
void main(){
foo(1,2); // packing
}
Ideal for UFCS would be:
{a,b}.zip.map!({x,y}=>x+y);
It is therefore likely that people will start to write two overloads, where one takes multiple arguments and the other takes one tuple argument.
|
March 29, 2013 Re: DIP32: Uniform tuple syntax | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dmitry Olshansky | Another reason to allow swapping values ( {a, b} = {b, a} ) is nice parallel semantics that might provide cool features on some future (or niche) parallel hardware. Think of {a, b} = {funcA(), funcB()}; Parallel semantics is able to evolve to parallel execution, which is one cool feature. In Go language it is so. |
March 29, 2013 Re: DIP32: Uniform tuple syntax | ||||
---|---|---|---|---|
| ||||
Posted in reply to kenji hara | kenji hara: > http://wiki.dlang.org/DIP32 Regarding case values: > switch (tup) { > case {1, 2}: > case {$, 2}: > case {1, x}: // capture tup[1] into 'x' when tup[0] == 1 > default: // same as {...} > } It's useful to switch on struct values: import std.bigint; void main() { auto x = BigInt(3); switch (x) { case BigInt(0): break; default: break; } } Other examples of Phobos structs that is useful to switch on are Nullable, Algebraic, etc. Switching on structs is more easy if the struct has no ctor. So it's a POD (despite having some other method). To support the general case of structs that have a constructor such structs need a standard method named like "unapply", that is used by the switch itself. This is the solution used by Scala language: http://www.scala-lang.org/node/112 This example is in Scala language: object Twice { def apply(x: Int): Int = x * 2 def unapply(z: Int): Option[Int] = if (z%2 == 0) Some(z/2) else None } object TwiceTest extends Application { val x = Twice(21) x match { case Twice(n) => Console.println(n) } // prints 21 } It's equivalent to the D code: import std.stdio; import std.typecons: Nullable; struct Twice { int static opCall(int x) { return x * 2; } Nullable!int unapply(int z) { if (z % 2 == 0) return typeof(return)(z / 2); else return typeof(return).init; } } void main() { immutable int x = Twice(21); assert(x == 42); switch (x) { case Twice(n): writeln(n); // prints 21 break; default: } } A different example: import std.stdio; import std.typecons: Nullable; struct Foo { int x; this(int x_) { this.x = x_ * 2; } Nullable!int unapply(Foo f1) const { return typeof(return)(f1.x / 2); } } void main() { immutable Foo f2 = Foo(10); assert(f1.x == 20); switch (f2) { case Foo(5): writeln("First case: 5"); break; case Foo(n): writeln(n); // Prints: 10 break; default: } } A third example: import std.stdio; struct Even { bool unapply(int x) { return x % 2 == 0; } } void main() { int x = 17; switch (x) { case Even(): writeln("even"); break; default: writeln("odd"); } } unapply() is allowed to return a bool or a Nullable (including a Nullable of a tuple). For more info: http://lamp.epfl.ch/~emir/written/MatchingObjectsWithPatterns-TR.pdf Bye, bearophile |
March 30, 2013 Re: DIP32: Uniform tuple syntax | ||||
---|---|---|---|---|
| ||||
not 'open', there is already something called .expand property http://forum.dlang.org/thread/fdkalkzhchuerkqlpzkg@forum.dlang.org how about this: auto x = {1,2,3}; auto x2 = {1,2}; assert(x[0..2]==x2);//no expansion void fun(int x, int y); fun(x2.expand); fun(x[0..2].expand); keeps slicing orthogonal from expansion > On Fri, Mar 29, 2013 at 10:31 AM, Timon Gehr <timon.gehr@gmx.ch> wrote: >> On 03/29/2013 05:39 PM, kenji hara wrote: >>> >>> 2013/3/30 bearophile <bearophileHUGS@lycos.com <mailto:bearophileHUGS@lycos.com>> >>> >>> >>> kenji hara: >>> >>> >>> I think it will become reasonable. If you really want re-packing >>> tuple, you >>> can use {tup[0..1]}. It's quite handy. >>> >>> >>> This is a bad idea. It is not handy and it introduces a special >>> case. Explicit is better than implicit. >>> >>> >>> That is "explicit". In D, opened tuple (currently it's generated from template parameters, e.g. std.typetuple.TypeTuple) and closed tuple (currently created by structs with alias tuple_field this; e.g. std.typecons.Tuple) are distinct. Slice operator always returns opened tuple. >> >> >> Because of prior language limitations, not because it makes any sense! >> >> Current operator overloading limitations mandate that it is simply not possible to create a Phobos tuple with a sane slice operator. >> >>> If tup[0..1] makes closed tuple implicitly, you cannot make new flattened tuple from other tuples. >>> >>> auto x = {1,"hi"}; >>> auto y = {[1,2], S(1)}; >>> auto tup1 = {x[], y[]}; // creates {1,"hi", [1,2], S(1)} >>> auto tup2 = {x, y}; // creates {{1,"hi"}, {[1,2], S(1)}} >>> >>> Under your semantics, it is impossible. >>> ... >> >> >> Certainly not. Creating opened tuples from closed ones is not an operation necessarily tied to slicing. >> >> Making an opened tuple should be an explicit operation on closed tuples. Slicing and opening are orthogonal operations. >> >> auto tup1 = {x.open, y.open}; // creates {1,"hi", [1,2], S(1)} >> auto tup2 = {x[0..2], y[]}; // creates {{1,"hi}, {[1,2], S(1)}} >> >> auto tup3 = {x[0..2].open, y[].open}; // creates {1,"hi", [1,2], S(1)} |
March 30, 2013 Re: DIP32: Uniform tuple syntax | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | On Friday, 29 March 2013 at 12:56:10 UTC, bearophile wrote:
> $ is used for array lengths, so it's not so good to overload it to mean "don't care" too.
>
> Alternative syntaxes:
>
> {c, $_} = tup;
> {c, @} = tup;
> {c, @_} = tup;
> {c, $$} = tup;
> {c, {}} = tup;
> {c, {_}} = tup;
> {c, $~} = tup;
> {c, @~= tup;
> etc.
{c, ?} = tup;
|
March 30, 2013 Re: DIP32: Uniform tuple syntax | ||||
---|---|---|---|---|
| ||||
Posted in reply to Zach the Mystic | Zach the Mystic:
>> {c, $_} = tup;
>> {c, @} = tup;
>> {c, @_} = tup;
>> {c, $$} = tup;
>> {c, {}} = tup;
>> {c, {_}} = tup;
>> {c, $~} = tup;
>> {c, @~= tup;
>> etc.
>
> {c, ?} = tup;
Right, I was forgetting that.
Or this if you want to keep the single "?" for hypothetical future nullable types:
{c, ?_} = tup;
Bye,
bearophile
|
March 31, 2013 Re: DIP32: Uniform tuple syntax | ||||
---|---|---|---|---|
| ||||
Posted in reply to Timon Gehr | On Friday, 29 March 2013 at 15:47:52 UTC, Timon Gehr wrote:
>> template X(T...) {}
>> alias x = X!(int, long); // T captures {int, long}
>>
>
> Not really. T captures {int, long}.expand.
Should there be a difference?
|
Copyright © 1999-2021 by the D Language Foundation