digitalmars.D - std.range: Order of arguments unluckily chosen?
- Timon Gehr (26/26) Jun 04 2011 From my code:
- Andrej Mitrovic (5/5) Jun 04 2011 I'd kill for some UFCS action. Here's my interpretation (only the
- Andrej Mitrovic (3/3) Jun 04 2011 Oh and I managed to screw up the second one, which should be:
- bearophile (17/24) Jun 04 2011 This is quite true. The order of all Haskell Prelude functions are desig...
- Andrei Alexandrescu (7/32) Jun 04 2011 Well this hurts. With the same in mind as you, I initially defined take
- Michel Fortin (18/31) Jun 04 2011 Perhaps like this:
- Timon Gehr (19/35) Jun 04 2011 I was about to propose the same. It also nicely disallows cases where UF...
- Mehrdad (3/16) Jun 04 2011 +1 for the idea, it's pretty similar to C#'s extension method syntax,
- so (8/33) Jun 06 2011 Nice idea to make sense out of the UFCS, but i fail to realize the
- Timon Gehr (14/20) Jun 06 2011 I think it is about readability of nested statements:
- so (3/20) Jun 06 2011 I agree.
- so (14/19) Jun 06 2011 This is the reason of quite many of the discussions here boils down to, ...
- KennyTM~ (6/12) Jun 06 2011 You could provide an overload?
From my code: writeln(reduce!"a+b"(stride(take(recurrence!"a[n-2]+a[n-1]"(2,3),31),3))); (This solves project euler problem 3); I think that should look more like: writeln(reduce!"a+b"(stride(3,take(31,recurrence!"a[n-2]+a[n-1]"(2,3))))); rationale: The second version is WAY easier to read, all the information needed is there without having to jump around in the code: 1st version translated to English: Sum up every j-th element of the first i elements of fib, which is computed by the recurrence a[n]=a[n-2]+a[n-1] with a[0]=2 and a[1]=3, where i=31 and j=3. 2nd version translated to English: Sum up every 3th element of the first 31 elements of fib, which is computed by the recurrence a[n]=a[n-2]+a[n-1] with a[0]=2 and a[1]=3. 1st version English is even better than the code, because you can search the text for 'i' or 'j'. In the code you have to count parentheses. Yes, changing the order would break UFCS. But UFCS works with arrays only, all the other use cases are broken. (that are most cases) Also, there is a function takeOne. That is more similar to take(1,...) than take(...,1). The amount of elements taken should be closer to the name of the action, because it is needed to fully describe it. (take!31(fib) would be even closer, but that does not work with runtime values.) I think the order should be swapped. It is also the way functional language libraries handle it. It works better with currying too. Any comments/arguments on why the current order is the right order? Timon
Jun 04 2011
I'd kill for some UFCS action. Here's my interpretation (only the first one works of course): range = take(stride(cycle([1, 2, 3, 4]), 2), 2); // :( range = take(stride(2, cycle(2, [1, 2, 3, 4]))); // :) range = cycle([1, 2, 3, 4]).stride(2).take(2); // :D
Jun 04 2011
Oh and I managed to screw up the second one, which should be: range = take(2, stride(2, cycle([1, 2, 3, 4]))); // :) All the more reason to have UFCS.
Jun 04 2011
Timon Gehr:It is also the way functional language libraries handle it. It works better with currying too.This is quite true. The order of all Haskell Prelude functions are designed to allow the most handy usage of currying: Prelude> let a = [0..10] Prelude> a [0,1,2,3,4,5,6,7,8,9,10] Prelude> take5 = take 5 Prelude> take5 a [0,1,2,3,4] If you program in Haskell you find that it's actually more handy to have the number of items of take as first argument. -------------------- Andrej Mitrovic:I'd kill for some UFCS action. Here's my interpretation (only the first one works of course): range = take(stride(cycle([1, 2, 3, 4]), 2), 2); // :( range = take(stride(2, cycle(2, [1, 2, 3, 4]))); // :) range = cycle([1, 2, 3, 4]).stride(2).take(2); // :DHaskell solves this problem with two really handy operators, "." and "$", example: stride _ [] = [] stride n (x:xs) = x : stride n (drop (n-1) xs) main = print $ take 2 $ cycle $ stride 2 [1, 2, 3, 4] Bye, bearophile
Jun 04 2011
On 06/04/2011 03:11 PM, Timon Gehr wrote:From my code: writeln(reduce!"a+b"(stride(take(recurrence!"a[n-2]+a[n-1]"(2,3),31),3))); (This solves project euler problem 3); I think that should look more like: writeln(reduce!"a+b"(stride(3,take(31,recurrence!"a[n-2]+a[n-1]"(2,3))))); rationale: The second version is WAY easier to read, all the information needed is there without having to jump around in the code: 1st version translated to English: Sum up every j-th element of the first i elements of fib, which is computed by the recurrence a[n]=a[n-2]+a[n-1] with a[0]=2 and a[1]=3, where i=31 and j=3. 2nd version translated to English: Sum up every 3th element of the first 31 elements of fib, which is computed by the recurrence a[n]=a[n-2]+a[n-1] with a[0]=2 and a[1]=3. 1st version English is even better than the code, because you can search the text for 'i' or 'j'. In the code you have to count parentheses. Yes, changing the order would break UFCS. But UFCS works with arrays only, all the other use cases are broken. (that are most cases) Also, there is a function takeOne. That is more similar to take(1,...) than take(...,1). The amount of elements taken should be closer to the name of the action, because it is needed to fully describe it. (take!31(fib) would be even closer, but that does not work with runtime values.) I think the order should be swapped. It is also the way functional language libraries handle it. It works better with currying too. Any comments/arguments on why the current order is the right order?Well this hurts. With the same in mind as you, I initially defined take to take the number first. But OO people wanted to write array.take(3), so I changed the order. Don't forget that UFCS is still on the table. Impossible to please everybody! I don't know what to do to improve the situation. Andrei
Jun 04 2011
On 2011-06-04 18:55:54 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> said:On 06/04/2011 03:11 PM, Timon Gehr wrote:Perhaps like this: auto take(R)(uint count, R this) { ... } Note that the second parameters's name is "this", which would mean that the second argument is the one that disappear using the member syntax. It can then be called this way: take(3, range); or this way: range.take(3); Having to specify explicitly whether a function is meant for member-syntax this way would also fix a couple of issues regarding UFCS: UFCS properties would be able to work correctly, and name clashes would happen less often when using the member syntax. -- Michel Fortin michel.fortin michelf.com http://michelf.com/I think the order should be swapped. It is also the way functional language libraries handle it. It works better with currying too. Any comments/arguments on why the current order is the right order?Well this hurts. With the same in mind as you, I initially defined take to take the number first. But OO people wanted to write array.take(3), so I changed the order. Don't forget that UFCS is still on the table. Impossible to please everybody! I don't know what to do to improve the situation.
Jun 04 2011
Michel Fortin wrote:Perhaps like this: auto take(R)(uint count, R this) { ... } Note that the second parameters's name is "this", which would mean that the second argument is the one that disappear using the member syntax. It can then be called this way: take(3, range); or this way: range.take(3); Having to specify explicitly whether a function is meant for member-syntax this way would also fix a couple of issues regarding UFCS: UFCS properties would be able to work correctly, and name clashes would happen less often when using the member syntax. -- Michel Fortin michel.fortin michelf.com http://michelf.com/I was about to propose the same. It also nicely disallows cases where UFCS is actually quite nonsensical, like Eg. y.atan2(x); But since it requires a language change, we'll be waiting a long time for it. (Even though everyone on this newsgroup seems to be talking about UFCS a lot.) How would the function make use of the parameter? I suggest that an explicit "this" should be required. (making it just a specially named parameter) Also, it would have to be discussed if structures and classes can define member functions using this syntax. I suggest to disallow it for non-static methods. in proposal, because it can be applied to the first parameter only. I am a bit concerned about this though: int foo(int a, int this, int c); foo(1,2,3); <=> (2).foo(1,3); // somewhat strange Is there any use case for that? Timon
Jun 04 2011
On 6/4/2011 4:25 PM, Michel Fortin wrote:Perhaps like this: auto take(R)(uint count, R this) { ... } Note that the second parameters's name is "this", which would mean that the second argument is the one that disappear using the member syntax. It can then be called this way: take(3, range); or this way: range.take(3); Having to specify explicitly whether a function is meant for member-syntax this way would also fix a couple of issues regarding UFCS: UFCS properties would be able to work correctly, and name clashes would happen less often when using the member syntax.and it's pretty intuitive IMHO.
Jun 04 2011
On Sun, 05 Jun 2011 02:25:46 +0300, Michel Fortin <michel.fortin michelf.com> wrote:On 2011-06-04 18:55:54 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> said:Nice idea to make sense out of the UFCS, but i fail to realize the actually need for UFCS to begin with. To me, the need to convert "take(3, range)" to "range.take(3)" is non-existent (and this wouldn't be the only reason i could come up with), probably i am missing something. And because everyone likes this, it must be something big :)On 06/04/2011 03:11 PM, Timon Gehr wrote:Perhaps like this: auto take(R)(uint count, R this) { ... } Note that the second parameters's name is "this", which would mean that the second argument is the one that disappear using the member syntax. It can then be called this way: take(3, range); or this way: range.take(3); Having to specify explicitly whether a function is meant for member-syntax this way would also fix a couple of issues regarding UFCS: UFCS properties would be able to work correctly, and name clashes would happen less often when using the member syntax.I think the order should be swapped. It is also the way functional language libraries handle it. It works better with currying too. Any comments/arguments on why the current order is the right order?Well this hurts. With the same in mind as you, I initially defined take to take the number first. But OO people wanted to write array.take(3), so I changed the order. Don't forget that UFCS is still on the table. Impossible to please everybody! I don't know what to do to improve the situation.
Jun 06 2011
so wrote:Nice idea to make sense out of the UFCS, but i fail to realize the actually need for UFCS to begin with. To me, the need to convert "take(3, range)" to "range.take(3)" is non-existent (and this wouldn't be the only reason i could come up with), probably i am missing something. And because everyone likes this, it must be something big :)I think it is about readability of nested statements: take(10,stride(2,cycle([3,2,5,3]))); vs. [3,2,5,3].cycle().stride(2).take(10); The first one is: "Take 10 of every 2nd element of cyclic [3,2,5,3,...]. The second one is: "Start with [3,2,5,3]. Then cycle that. Then only look at every 2nd element of that. Finally, take 10 elements out of the resulting range." The second version writes the actions in the order they are performed, while the functional way is more like what you'd get if you had to describe the entire process in a single sentence. It also reduces nesting of parentheses. I am fine with both. But I dislike take(stride(cycle([3,2,5,3]),2),10); Timon
Jun 06 2011
I think it is about readability of nested statements: take(10,stride(2,cycle([3,2,5,3]))); vs. [3,2,5,3].cycle().stride(2).take(10); The first one is: "Take 10 of every 2nd element of cyclic [3,2,5,3,...]. The second one is: "Start with [3,2,5,3]. Then cycle that. Then only look at every 2nd element of that. Finally, take 10 elements out of the resulting range."Thanks, this alone makes me realize the need for UFCS. Until now i was thinking it is just about taste, look, that some people like the OO way.The second version writes the actions in the order they are performed, while the functional way is more like what you'd get if you had to describe the entire process in a single sentence. It also reduces nesting of parentheses. I am fine with both. But I dislike take(stride(cycle([3,2,5,3]),2),10);I agree.
Jun 06 2011
Well this hurts. With the same in mind as you, I initially defined take to take the number first. But OO people wanted to write array.take(3), so I changed the order. Don't forget that UFCS is still on the table. Impossible to please everybody! I don't know what to do to improve the situation.This is the reason of quite many of the discussions here boils down to, we (not being a contributor, maybe i should say "you") shouldn't cater for particular groups be it either Functional or OO. If they don't feel something right, they should also consider the other side of the table, and come up with compelling arguments. Reading recent posts, i really started to think the word "subjectivity" is just a horse-waste to divert our attention. Given none of our backgrounds match one another, none of our experiences match with one another, none of our open/close mindedness match with one another. I like OO more than most of the people here, but it is simply a freaking paradigm. If some people just want everything OO way, knowing none of its drawbacks... Forgive my language, fuck them. We have many languages out there just doing that, and yet the only reason we are here is that we know they suck.
Jun 06 2011
On Jun 5, 11 06:55, Andrei Alexandrescu wrote:Well this hurts. With the same in mind as you, I initially defined take to take the number first. But OO people wanted to write array.take(3), so I changed the order. Don't forget that UFCS is still on the table. Impossible to please everybody! I don't know what to do to improve the situation. AndreiYou could provide an overload? Take!R take(R)(size_t n, R input) if (!is(Unqual!R : size_t)) { return take(input, n); } Like PHP's implode() ;).
Jun 06 2011