June 17, 2013 Re: How to expand an expression along with a parameter tuple? | ||||
---|---|---|---|---|
| ||||
Posted in reply to TommiT | On 06/17/2013 02:32 AM, TommiT wrote: > On Monday, 17 June 2013 at 07:20:23 UTC, Ali Çehreli wrote: >> >> The following does not answer the question of expanding but at least >> foo() receives [30, 70, 110] :) >> >> import std.stdio; >> import std.algorithm; >> import std.array; >> import std.range; >> >> int[] arr = [ 1, 3, 5, 7, 11 ]; >> >> void foo(T)(T[] values...) >> { >> writeln(values); >> } >> >> void bar(T)(T[] values...) >> { >> foo(arr >> .indexed(values) >> .map!(a => a * 10) >> .array); >> } >> >> void main() >> { >> bar(1, 3, 4); >> } >> >> Ali > > Yeah, that would work. I'd hate the overhead though. There is no inherent overhead though. I called .array only because I thought that the C++ version was eager. If we stay lazy and D-like, we can make foo() take a range: import std.stdio; import std.algorithm; import std.range; int[] arr = [ 1, 3, 5, 7, 11 ]; void foo(R)(R range) // <-- now takes range { writeln(range); } void bar(T)(T[] values...) { foo(arr .indexed(values) .map!(a => a * 10)); // <-- no .array anymore } void main() { bar(1, 3, 4); } I hear that ldc (and perhaps gdc) perform pretty magical compiler optimizations. There is no reason for the code above to be slower than the hand-written equivalent. Ali |
June 17, 2013 Re: How to expand an expression along with a parameter tuple? | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | On 06/17/13 16:20, bearophile wrote: > Artur Skawina: > >> Yes, this is not as concise as '...' would be. But, with a bit more tuple support in the language, the '.tuple' part wouldn't be >> necessary, > > Implicit things are dangerous in languages. Not sure what you mean. "A bit more tuple support" means aot being able to return /real/ tuples from functions. This just needs to be specced; can be handled like I did in the ForEach example - by wrapping it in a struct, only internally. Then this becomes possible: auto ForEach(alias MAP, TS...)(TS ts) { NTup!(TS.length, typeof(MAP(TS[0].init))) tuple; foreach (i, ref v; values) tuple[i] = MAP(v); return tuple; } void bar(T...)(T values) { foo(ForEach!(a=>arr[a]*10)(values)); } which is already much more readable. And 100% explicit. While /it's only syntax sugar/, it does remove a lot of noise. > ".tuple" can also be written "[]". No idea what you mean by this. artur |
June 17, 2013 Re: How to expand an expression along with a parameter tuple? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Artur Skawina | Artur Skawina:
>> ".tuple" can also be written "[]".
>
> No idea what you mean by this.
If in the code you wrote you replace the first ".tuple" with "[]" the code keeps working.
Bye,
bearophile
|
June 17, 2013 Re: How to expand an expression along with a parameter tuple? | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | On 06/17/13 23:11, bearophile wrote:
> Artur Skawina:
>
>>> ".tuple" can also be written "[]".
>>
>> No idea what you mean by this.
>
> If in the code you wrote you replace the first ".tuple" with "[]" the code keeps working.
It does not - I really have no idea what you mean; slicing a struct
does not (and can not) produce an auto-expanding tuple, unless I'm missing
some recent language change...
artur
|
June 18, 2013 Re: How to expand an expression along with a parameter tuple? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Artur Skawina | On Monday, 17 June 2013 at 13:59:34 UTC, Artur Skawina wrote:
>
> Another solution would be to have the following hidden in some lib:
>
> struct _ForEach(alias MAP, TS...) {
> NTup!(TS.length, typeof(MAP(TS[0].init))) tuple;
>
> this(TS values) {
> foreach (i, ref v; values)
> tuple[i] = MAP(v);
> }
> }
>
> auto ForEach(alias MAP, TS...)(TS ts) {
> return _ForEach!(MAP, TS)(ts);
> }
>
> Then 'bar' becomes just:
>
> void bar(T...)(T values) {
> foo(ForEach!(a=>arr[a]*10)(values).tuple);
> }
>
> Yes, this is not as concise as '...' would be. But, with a bit more
> tuple support in the language, the '.tuple' part wouldn't be
> necessary, and then it's just
>
> foo(ForEach!(a=>arr[a]*10)(values));
> vs
> foo((arr[values] * 10)...);
>
> artur
Now, this is pretty cool. But I wonder a couple of things:
1) What kind of an impact does this have on compilation times compared to having this new ellipsis syntax which would allow the compiler to do a simple rewrite.
2) I wonder if the compiler can optimize that _ForEach struct away.
|
June 18, 2013 Re: How to expand an expression along with a parameter tuple? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Artur Skawina | On Monday, 17 June 2013 at 13:59:34 UTC, Artur Skawina wrote:
> [..]
Your setup has a pretty serious issue with correctness though. It's because all the types of _ForEach.tuple are the same as the first element of TS...
import std.stdio;
template NTup(size_t N, T...)
{
static if (N > 1)
alias NTup = NTup!(N-1, T, T[$-1]);
else
alias NTup = T;
}
struct _ForEach(alias MAP, TS...)
{
NTup!(TS.length, typeof(MAP(TS[0].init))) tuple;
this(TS values)
{
foreach (i, ref v; values)
tuple[i] = MAP(v);
}
}
auto ForEach(alias MAP, TS...)(TS ts)
{
return _ForEach!(MAP, TS)(ts);
}
void foo(T...)(T values)
{
foreach (v; values)
writeln(v);
}
void bar(T...)(T values)
{
foo(ForEach!(a => a + 1)(values).tuple);
}
void main()
{
bar(10, 3_000_000_000u);
}
-----
Prints:
11
-1294967295
Change the call to bar(1, 3L); and it wouldn't even compile.
|
June 18, 2013 Re: How to expand an expression along with a parameter tuple? | ||||
---|---|---|---|---|
| ||||
Posted in reply to TommiT | On Tuesday, 18 June 2013 at 02:37:46 UTC, TommiT wrote:
> It's because all the types of _ForEach.tuple are the same as the first element of TS...
I mean... the same as the type of MAP(TS[0])
|
June 18, 2013 Re: How to expand an expression along with a parameter tuple? | ||||
---|---|---|---|---|
| ||||
Posted in reply to TommiT | On 06/18/13 03:51, TommiT wrote: > On Monday, 17 June 2013 at 13:59:34 UTC, Artur Skawina wrote: >> >> struct _ForEach(alias MAP, TS...) { >> NTup!(TS.length, typeof(MAP(TS[0].init))) tuple; >> >> this(TS values) { >> foreach (i, ref v; values) >> tuple[i] = MAP(v); >> } >> } >> >> auto ForEach(alias MAP, TS...)(TS ts) { >> return _ForEach!(MAP, TS)(ts); >> } >> >> void bar(T...)(T values) { >> foo(ForEach!(a=>arr[a]*10)(values).tuple); >> } > Now, this is pretty cool. But I wonder a couple of things: > 1) What kind of an impact does this have on compilation times compared to having this new ellipsis syntax which would allow the compiler to do a simple rewrite. Not a significant one, I'd expect; for simple cases like these it shouldn't make much difference. > 2) I wonder if the compiler can optimize that _ForEach struct away. Yes. > Change the call to bar(1, 3L); and it wouldn't even compile. > It's because all the types of _ForEach.tuple are the same as the first element of TS... > > I mean... the same as the type of MAP(TS[0]) That was enough to handle the original problem, iirc. Making the code work for heterogeneous args (and mapping functions) is trivial, though: import std.stdio; template _TypeMap(alias MAP, size_t N, TS...) { static if (N<TS.length) alias _TypeMap = _TypeMap!(MAP, N+1, TS[0..N], typeof(MAP(TS[N].init), TS[N..$])); else alias _TypeMap = TS; } template TypeMap(alias MAP, TS...) { alias TypeMap = _TypeMap!(MAP, 0, TS); } struct _ForEach(alias MAP, TS...) { TypeMap!(MAP, TS) tuple; this(TS values) { foreach (i, ref v; values) tuple[i] = MAP(v); } } auto ForEach(alias MAP, TS...)(TS ts) { return _ForEach!(MAP, TS)(ts); } void foo(T...)(T values) { foreach (v; values) writeln(v); } void bar(T...)(T values) { foo(ForEach!(a => a + 1)(values).tuple); } void main() { bar(10, 3_000_000_000u, 2.14, -43L); } artur |
June 18, 2013 Re: How to expand an expression along with a parameter tuple? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Artur Skawina | Artur Skawina:
> slicing a struct
> does not (and can not) produce an auto-expanding tuple, unless I'm missing
> some recent language change...
Sorry, I have misunderstood the type, the [] works on typetuples.
Bye,
bearophile
|
June 18, 2013 Re: How to expand an expression along with a parameter tuple? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Artur Skawina | On Tuesday, 18 June 2013 at 10:57:00 UTC, Artur Skawina wrote:
> On 06/18/13 03:51, TommiT wrote:
>> Change the call to bar(1, 3L); and it wouldn't even compile.
>> It's because all the types of _ForEach.tuple are the same as the first element of TS...
>>
>> I mean... the same as the type of MAP(TS[0])
>
> That was enough to handle the original problem, iirc.
> Making the code work for heterogeneous args (and mapping functions) is
> trivial, though:
>
> import std.stdio;
>
> template _TypeMap(alias MAP, size_t N, TS...) {
> static if (N<TS.length)
> alias _TypeMap = _TypeMap!(MAP, N+1, TS[0..N], typeof(MAP(TS[N].init), TS[N..$]));
> else
> alias _TypeMap = TS;
> }
> template TypeMap(alias MAP, TS...) {
> alias TypeMap = _TypeMap!(MAP, 0, TS);
> }
>
> struct _ForEach(alias MAP, TS...)
> {
> TypeMap!(MAP, TS) tuple;
>
> this(TS values)
> {
> foreach (i, ref v; values)
> tuple[i] = MAP(v);
> }
> }
>
> auto ForEach(alias MAP, TS...)(TS ts)
> {
> return _ForEach!(MAP, TS)(ts);
> }
>
> void foo(T...)(T values)
> {
> foreach (v; values)
> writeln(v);
> }
>
> void bar(T...)(T values)
> {
> foo(ForEach!(a => a + 1)(values).tuple);
> }
>
> void main()
> {
> bar(10, 3_000_000_000u, 2.14, -43L);
> }
>
>
> artur
Okay, you really seem to have figured this stuff out. I think I have difficulty seeing the solution because I'm used to C++ parameter packs, which have much less functionality than parameter tuples in D + there's no static if. But I learned a lot from this, thanks for that.
|
Copyright © 1999-2021 by the D Language Foundation