digitalmars.D.learn - Issue Turning Template into Variadic Template
- jmh530 (48/48) Mar 30 2016 I wrote a version of cartesianProduct that will return the
- H. S. Teoh via Digitalmars-d-learn (43/49) Mar 30 2016 [...]
- jmh530 (3/4) Mar 30 2016 I think it does. That's an approach I would not have thought of.
- jmh530 (11/12) Mar 30 2016 Okay, I've looked at this a bit more thoroughly and it works
- H. S. Teoh via Digitalmars-d-learn (19/34) Mar 30 2016 Yes.
- Artur Skawina via Digitalmars-d-learn (7/16) Mar 31 2016 auto mixedCartesianProduct(T...)(T x)
- jmh530 (2/9) Mar 31 2016 Thanks, but I try to only use mixins as a last resort.
- ag0aep6g (12/24) Mar 31 2016 auto mixedCartesianProduct(T...)(T x)
- H. S. Teoh via Digitalmars-d-learn (6/38) Mar 31 2016 +1, very nice. :-) Much more concise and to-the-point than my attempt.
I wrote a version of cartesianProduct that will return the cartesian product when the some of the types are not ranges. The original code is below. My issue is that I can't figure out how to turn it into a variadic template. The latest thing I tried is: auto mixedCartesianProduct(T...)(T x) { import std.algorithm : cartesianProduct; foreach(t; x) t = conditionalOnly(t); return cartesianProduct(x); } but this doesn't work because it changes the type of x. I don't really want to change the type of x. I just want to be able to pass the changed versions to cartesianProduct as in the original code below. map won't work for the same reasons. //Original: auto conditionalOnly(T)(T x) { import std.range : isInputRange; static if (isInputRange!T) return x; else { import std.range : only; return only(x); } } auto mixedCartesianProduct(T, U)(T x, U y) { import std.algorithm : cartesianProduct; return cartesianProduct(conditionalOnly(x), conditionalOnly(y)); } void main() { import std.stdio : writeln; import std.range : iota; auto a = 1; auto b = iota(2); auto c = mixedCartesianProduct(a, b); writeln(c); }
Mar 30 2016
On Wed, Mar 30, 2016 at 06:12:40PM +0000, jmh530 via Digitalmars-d-learn wrote:I wrote a version of cartesianProduct that will return the cartesian product when the some of the types are not ranges. The original code is below. My issue is that I can't figure out how to turn it into a variadic template. The latest thing I tried is:[...] Does this do what you want? import std.algorithm.setops : cartesianProduct; import std.range : only; import std.range.primitives; import std.meta : AliasSeq; template ImplType(T...) { static if (T.length == 0) alias ImplType = AliasSeq!(); else { static if (isInputRange!(T[0])) alias FirstType = T[0]; else alias FirstType = typeof(only(T[0].init)); alias ImplType = AliasSeq!(FirstType, ImplType!(T[1 .. $])); } } auto conditionalOnly(alias fun, T...)(T x) { ImplType!T y; foreach (i, e; x) { static if (isInputRange!(typeof(e))) y[i] = e; else y[i] = only(e); } return fun(y); } void main() { import std.stdio; writeln(conditionalOnly!cartesianProduct(1, [2, 3], 4, [5, 6])); } Note that conditionalOnly isn't specifically tied to cartesianProduct; you can use it on anything that receives a variadic number of range arguments. T -- "I'm not childish; I'm just in touch with the child within!" - RL
Mar 30 2016
On Wednesday, 30 March 2016 at 18:56:29 UTC, H. S. Teoh wrote:Does this do what you want?I think it does. That's an approach I would not have thought of. I do not really know much about AliasSeq.
Mar 30 2016
On Wednesday, 30 March 2016 at 18:56:29 UTC, H. S. Teoh wrote:Does this do what you want?Okay, I've looked at this a bit more thoroughly and it works perfectly (perhaps with a better name put in phobos?). If I'm understanding this correctly, the ImplType creates the correct type signature for the output and then conditionalOnly puts the right value in. One thing that is confusing is that when I create a new function that adjusts conditionalOnly to just return y instead of fun(y), then I get an error about returning a tuple. I'm like, where did I use a tuple. I guess related to https://issues.dlang.org/show_bug.cgi?id=15436
Mar 30 2016
On Wed, Mar 30, 2016 at 08:43:03PM +0000, jmh530 via Digitalmars-d-learn wrote:On Wednesday, 30 March 2016 at 18:56:29 UTC, H. S. Teoh wrote:Yes. It was a quick hack, though, and involves assigning the ranges to a local variable. There ought to be a way to pass the arguments directly, while substituting the non-ranges with only(x). But that would probably involve even more black magic that I'm already invoking. :-P It's pretty close to the point where I'd just throw up my hands and say, forget the template black magic shenanigans, just write a mixin and call it a day.Does this do what you want?Okay, I've looked at this a bit more thoroughly and it works perfectly (perhaps with a better name put in phobos?). If I'm understanding this correctly, the ImplType creates the correct type signature for the output and then conditionalOnly puts the right value in.One thing that is confusing is that when I create a new function that adjusts conditionalOnly to just return y instead of fun(y), then I get an error about returning a tuple. I'm like, where did I use a tuple. I guess related to https://issues.dlang.org/show_bug.cgi?id=15436Yes... basically the compiler is complaining that it doesn't know how to return a value with of AliasSeq type. Why it can't do this, is a complex question that I don't have the time to get into right now... but basically, if you want to return it instead of calling the target function, you have to wrap it in a std.typecons.Tuple struct (how's that for confusing terminology?!), and use .expand to unwrap it when you need to pass it to a function. T -- Always remember that you are unique. Just like everybody else. -- despair.com
Mar 30 2016
On 03/30/16 20:12, jmh530 via Digitalmars-d-learn wrote:I wrote a version of cartesianProduct that will return the cartesian product when the some of the types are not ranges. The original code is below. My issue is that I can't figure out how to turn it into a variadic template.auto mixedCartesianProduct(T, U)(T x, U y) { import std.algorithm : cartesianProduct; return cartesianProduct(conditionalOnly(x), conditionalOnly(y)); }auto mixedCartesianProduct(T...)(T x) { import std.range, std.algorithm : cartesianProduct; return mixin(`cartesianProduct(`~iota(T.length).map!`"conditionalOnly(x["~text(a)~"])"`().join(",")~`)`); } artur
Mar 31 2016
On Thursday, 31 March 2016 at 10:27:41 UTC, Artur Skawina wrote:auto mixedCartesianProduct(T...)(T x) { import std.range, std.algorithm : cartesianProduct; return mixin(`cartesianProduct(`~iota(T.length).map!`"conditionalOnly(x["~text(a)~"])"`().join(",")~`)`); } arturThanks, but I try to only use mixins as a last resort.
Mar 31 2016
On 30.03.2016 20:12, jmh530 wrote:I wrote a version of cartesianProduct that will return the cartesian product when the some of the types are not ranges. The original code is below. My issue is that I can't figure out how to turn it into a variadic template. The latest thing I tried is: auto mixedCartesianProduct(T...)(T x) { import std.algorithm : cartesianProduct; foreach(t; x) t = conditionalOnly(t); return cartesianProduct(x); }auto mixedCartesianProduct(T...)(T x) { import std.algorithm : cartesianProduct; import std.meta: staticMap; import std.traits : ReturnType; alias ConditionalOnly(T) = ReturnType!(conditionalOnly!T); alias RangeTypes = staticMap!(ConditionalOnly, T); RangeTypes ranges; foreach (i, t; x) ranges[i] = conditionalOnly(t); return cartesianProduct(ranges); }
Mar 31 2016
On Thu, Mar 31, 2016 at 07:43:38PM +0200, ag0aep6g via Digitalmars-d-learn wrote:On 30.03.2016 20:12, jmh530 wrote:+1, very nice. :-) Much more concise and to-the-point than my attempt. And how did I not remember we have staticMap in Phobos... :-P T -- Don't get stuck in a closet---wear yourself out.I wrote a version of cartesianProduct that will return the cartesian product when the some of the types are not ranges. The original code is below. My issue is that I can't figure out how to turn it into a variadic template. The latest thing I tried is: auto mixedCartesianProduct(T...)(T x) { import std.algorithm : cartesianProduct; foreach(t; x) t = conditionalOnly(t); return cartesianProduct(x); }auto mixedCartesianProduct(T...)(T x) { import std.algorithm : cartesianProduct; import std.meta: staticMap; import std.traits : ReturnType; alias ConditionalOnly(T) = ReturnType!(conditionalOnly!T); alias RangeTypes = staticMap!(ConditionalOnly, T); RangeTypes ranges; foreach (i, t; x) ranges[i] = conditionalOnly(t); return cartesianProduct(ranges); }
Mar 31 2016