digitalmars.D.learn - writeln, UFCS and flip
- bearophile (87/87) Apr 25 2013 writeln is able to write a whole range:
- bearophile (20/20) Apr 25 2013 This is not a real use case because the reduce!() of Phobos will
- ixid (2/2) Apr 25 2013 Doesn't binaryReverseArgs in std.functional already do this? Flip
- ixid (8/10) Apr 25 2013 Though I still think write functions passing on the data would be
- bearophile (6/10) Apr 25 2013 Right, it's the flip I have suggested here. My flip2 is a little
- Timon Gehr (2/5) Apr 25 2013 I think what you call flip2 should be called flip.
- bearophile (4/5) Apr 26 2013 Why?
- ixid (4/9) Apr 26 2013 flip2 is the more general and useful function with new
- bearophile (10/13) Apr 26 2013 I don't agree. Maybe you are missing something.
- Tyro[17] (4/17) Apr 26 2013 and this rotate....
- bearophile (6/12) Apr 26 2013 Really? Just swapping the first two arguments and leaving the
- Timon Gehr (3/14) Apr 26 2013 And there it flips the first two arguments (of a curried function, since...
- Tyro[17] (3/16) Apr 26 2013 Actually, by brain was thinking it but my eyes saw something completely
- Tyro[17] (11/32) Apr 26 2013 With that clarification, I just have one more question, since flip does
- bearophile (11/21) Apr 26 2013 flip2 swaps just the fist two arguments and leaves the others at
writeln is able to write a whole range: import std.stdio, std.algorithm, std.range; void main() { 10.iota.map!(x => x ^^ 2).writeln; } Output: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] - - - - - - - - - - - - - - - - But if you want to format the range in some way you have to change the order of things, this is not nice: import std.stdio, std.algorithm, std.range; void main() { writefln("%(%d %)", 10 .iota .map!(x => x ^^ 2)); } Output: 0 1 4 9 16 25 36 49 64 81 - - - - - - - - - - - - - - - - To solve that little problem I suggested to add some new printing functions to Phobos: http://d.puremagic.com/issues/show_bug.cgi?id=9882 auto uWrite(T)(T data) { write(data); return data; } auto uWriteln(T)(T data) { writeln(data); return data; } auto uWritef(T, TS)(T data, TS format) if (isSomeString!TS) { writef(format, data); return data; } auto uWritefln(T, TS)(T data, TS format) if (isSomeString!TS) { writefln(format, data); return data; } - - - - - - - - - - - - - - - - Now I have invented a different solution (similar to the "flip" function of Haskell): import std.stdio, std.algorithm, std.range; /// flip!foo(a, b) === foo(b, a) template flip(alias callable) { auto flip(T2, T1)(T2 y, T1 x) { return callable(x, y); } } void main() { 10.iota.map!(x => x ^^ 2).flip!writefln("%(%d %)"); } You can also write that main() like this: void main() { 10 .iota .map!(x => x ^^ 2) .flip!writefln("%(%d %)"); } (I have used a template+function so flip!foo is usable as argument for some algorithms.) flip is a much more general solution, and it's useful in other situations. In theory "callable" should have a template constraint like "isCallable!callable", but in practice I think you can't use it for writeln and other templated functions. - - - - - - - - - - - - - - - - An alternative design flips the first two arguments of two or more arguments: import std.stdio, std.algorithm, std.range; /// flip2!foo(a, b, c...) === foo(b, a, c...) template flip2(alias callable) { auto flip2(T2, T1n...)(T2 y, T1n others) if (T1n.length > 0) { return callable(others[0], y, others[1 .. $]); } } void main() { 10.iota.map!(x => x ^^ 2).flip2!writefln("%(%d %) %s", "good"); } I have named it flip2 because I expect this to be true: flip!foo(a, b, c) === foo(c, b, a) so the name "foo2" reminds me that it flips only the first two arguments. What do you think? Bye, bearophile
Apr 25 2013
This is not a real use case because the reduce!() of Phobos will be fixed for UCFS, but sometimes you can't swap the arguments of a function: import std.stdio, std.algorithm, std.range; /// flip2!foo(a, b, c...) === foo(b, a, c...) template flip2(alias callable) { auto flip2(T2, T1n...)(T2 y, T1n others) if (T1n.length > 0) { return callable(others[0], y, others[1 .. $]); } } void main() { reduce!q{a * b}(1, iota(1, 10)) .writeln; iota(1, 10) .flip2!(reduce!q{a * b})(1) .writeln; } Bye, bearophile
Apr 25 2013
Doesn't binaryReverseArgs in std.functional already do this? Flip is a much, much better name though.
Apr 25 2013
On Thursday, 25 April 2013 at 16:20:39 UTC, ixid wrote:Doesn't binaryReverseArgs in std.functional already do this? Flip is a much, much better name though.Though I still think write functions passing on the data would be useful, letting you avoid needless temporaries just so you can write the output of a function. It's useful for normal code as well as UFCS. string temp = myFun(); temp.writeln; result ~= temp ~ "\n";
Apr 25 2013
On Thursday, 25 April 2013 at 16:20:39 UTC, ixid wrote:Doesn't binaryReverseArgs in std.functional already do this?Right, it's the flip I have suggested here. My flip2 is a little different. I will think about this.Though I still think write functions passing on the data would be useful, letting you avoid needless temporaries just so you can write the output of a function.OK. Bye, bearophile
Apr 25 2013
On 04/25/2013 05:09 PM, bearophile wrote:... What do you think? ...I think what you call flip2 should be called flip.
Apr 25 2013
Timon Gehr:I think what you call flip2 should be called flip.Why? Bye, bearophile
Apr 26 2013
On Friday, 26 April 2013 at 10:52:09 UTC, bearophile wrote:Timon Gehr:flip2 is the more general and useful function with new functionality so there's no need for what was flip and we should call the new function 'flip'.I think what you call flip2 should be called flip.Why? Bye, bearophile
Apr 26 2013
ixid:flip2 is the more general and useful function with new functionality so there's no need for what was flip and we should call the new function 'flip'.I don't agree. Maybe you are missing something. I expect a function named "flip" to do: flip!foo(a, b, c) === foo(c, b, a) flip!foo(a, b, c, d) === foo(d, c, b, a) While flip2 does: flip2!foo(a, b, c) === foo(b, a, c) flip2!foo(a, b, c, d) === foo(b, a, c, d) Bye, bearophile
Apr 26 2013
On 4/26/13 8:59 AM, bearophile wrote:ixid:I would expect this to be called reverseflip2 is the more general and useful function with new functionality so there's no need for what was flip and we should call the new function 'flip'.I don't agree. Maybe you are missing something. I expect a function named "flip" to do: flip!foo(a, b, c) === foo(c, b, a) flip!foo(a, b, c, d) === foo(d, c, b, a)While flip2 does: flip2!foo(a, b, c) === foo(b, a, c) flip2!foo(a, b, c, d) === foo(b, a, c, d)and this rotate.... Why flip in the first place?Bye, bearophile
Apr 26 2013
Tyro[17]:Really? Just swapping the first two arguments and leaving the others at their place is for a "rotate"?While flip2 does: flip2!foo(a, b, c) === foo(b, a, c) flip2!foo(a, b, c, d) === foo(b, a, c, d)and this rotate....Why flip in the first place?I don't know, it's the name used in the Haskell Prelude. Bye, bearophile
Apr 26 2013
On 04/26/2013 10:15 PM, bearophile wrote:Tyro[17]:And there it flips the first two arguments (of a curried function, since this is the standard for Haskell).Really? Just swapping the first two arguments and leaving the others at their place is for a "rotate"?While flip2 does: flip2!foo(a, b, c) === foo(b, a, c) flip2!foo(a, b, c, d) === foo(b, a, c, d)and this rotate....Why flip in the first place?I don't know, it's the name used in the Haskell Prelude.
Apr 26 2013
On 4/26/13 4:15 PM, bearophile wrote:Tyro[17]:Actually, by brain was thinking it but my eyes saw something completely different. You are correct, this what I would expect flip to do. Thanks.Really? Just swapping the first two arguments and leaving the others at their place is for a "rotate"?While flip2 does: flip2!foo(a, b, c) === foo(b, a, c) flip2!foo(a, b, c, d) === foo(b, a, c, d)and this rotate....Why flip in the first place?I don't know, it's the name used in the Haskell Prelude. Bye, bearophile
Apr 26 2013
On 4/26/13 5:09 PM, Tyro[17] wrote:On 4/26/13 4:15 PM, bearophile wrote:With that clarification, I just have one more question, since flip does what is intuitively implied by a reverse function and flip2 does what is intuitively implied by a flip function, why not name them as such? Understand the Haskell influence and all but, influence notwithstanding, this is D so why not designate functions in a manner that intuitively imply functionality? I would expect a flip and flip2 if both accomplish the exact same thing but both outperforms the other in certain scenarios thus warranting both to be present. AndrewTyro[17]:Actually, by brain was thinking it but my eyes saw something completely different. You are correct, this what I would expect flip to do. Thanks.Really? Just swapping the first two arguments and leaving the others at their place is for a "rotate"?While flip2 does: flip2!foo(a, b, c) === foo(b, a, c) flip2!foo(a, b, c, d) === foo(b, a, c, d)and this rotate....Why flip in the first place?I don't know, it's the name used in the Haskell Prelude. Bye, bearophile
Apr 26 2013
Tyro[17]:With that clarification, I just have one more question, since flip does what is intuitively implied by a reverse functionOK, better to name it reversedArgs :-)and flip2 does what is intuitively implied by a flip function,flip2 swaps just the fist two arguments and leaves the others at their place.I would expect a flip and flip2 if both accomplish the exact same thing but both outperforms the other in certain scenarios thus warranting both to be present.I think that the caos of this thread shows that keeping both will cause confusion :-(why not name them as such? Understand the Haskell influence and all but, influence notwithstanding, this is D so why not designate functions in a manner that intuitively imply functionality?I am starting to agree with Andrei. Short function names are handy, but in many situations the semantic confusion they can bring is not worth it. More food for thought for me. Bye, bearophile
Apr 26 2013