(1..100).inject(&:+)
weblog.raganwald.com
weblog.raganwald.com
For what it's worth,
(1..100).to_a.sum
works in Rails, though
(1..100).sum
doesn't.
(http://news.ycombinator.com/item?id=123071 if you don't know to which I am referring.)
The truth is, I wrote the idea behind this a while back using String#to_proc to compare the way Ruby (roll your own) and Python (Guido decides) evolve. But considering I have no Python experience, I never published the post.
Then today, for some reason, I was thinking about Open Classes again :-)
I know a pretty large number of languages to the point where, unless it's LISP, I can look at code in any language and have some idea of what it does. When a languages gets "so cool" that it's cryptic than I no longer see the benefit.
Please let me know if changing the name of the method doesn't help.
'inject' makes sense (in retrospect), but until it was explained, I had no clue why injecting symbol soup into a range of integers was interesting.
Lisp flavours?
"A little explanation in your article would've been fine."
Done, thank you.
+/!100
4950
Or if you insist on 1-indexing: +/1+!100
5050You are correct in supposing that !n generates an array of integers from 0 to n-1. It is somewhat of an unusual choice for a symbol. I've always thought of it as a factorial 'on the other side'. I don't know if that's what was intended. The k language compresses many old APL functions into symbols like this. Some make sense, some make less sense. You are after all dependent on your keyboard for the range of symbols you can type. In APL the same function was indicated by a lowercase Greek iota.
'+' is being used in two different ways. The first way shows it being used in conjunction with an adverb, so '+/' is like a one-argument function that gets applied to the list at the right, but then '+' is inserted between each of the elements of the list because of '/'.
'\' is a very similar adverb. It's called 'scan', and it's like 'over', except intermediate output is produced. It can help illustrate what's going on.
!100
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 ..
+/!100
4950
+\!100
0 1 3 6 10 15 21 28 36 45 55 66 78 91 105 120 136 153 171 190 210 231 253 276..
In the second case, '+' is being used as an infix operator, taking two arguments, 1 and !100, so '+' adds 1 to each element in the list 0 to 99, inclusive. This is simply what happens when you add an atom to a list. Each element in the list gets incremented by the value of the atom. Most verbs in k are like this, in that they do what you want, or maybe, they do what they should do if your preference is for something to occur rather than for an error to be thrown. 5 + 0 1 2
5 6 7
5 + !3
5 6 7
1 2 3 + 4 5 6
5 7 9
1 2 + 4 5 6
'length (an error) (1..100).inject { |acc, n| acc + n }
inject is a left fold or a reduce- it applies the function {acc + n} to each element in a list (or array) where acc is the result of the last function application.For such a simple function, all we need is the knowledge that we are adding, which is contained in the symbol '+', representing the addition method. So Ideally we would like to write
(1..100).inject( :+ )
The semicolon is how you tell ruby you are using a symbol.
Yes, you can write a simple sum function, but the point is that this code is more flexible in a very powerful way- we can use other functions then inject and add.Method calling in Ruby is actually message passing. So instead of calling
1.+ 2 # => 3
You can say 1.send( :+, 2 ) # => 3
So we are not trying to convert a symbol to a proc. What we are trying to do is continually send the message ':+' to inject's built in accumulator, with every member of the list (or array) as an argument.In ruby, the brackets are like a function, but it is actually a closure of class Proc. You can convert a different class to a proc (if it supports it) by calling to_proc.
Ruby has a syntactic shortcut, '&' for converting to a proc. Normally it actually makes the code clearer because it is also used when passing Procs onto other methods, and is a nice type annotation. So we can hack this syntactic shortcut to create
(1..100).inject( &:+ )
So by defining how '&' works by defining to_proc, we can make it create a closure (or Proc) which sends the ':+' symbol, along with any arguments that are yielded to the Proc. In this case, every value from (2..100) is yielded to the Proc. (1 will be the starting value of the accumulator.)You can accomplish a lot of things with a closure, including this hack. But to me this shows that ruby was not designed as a functional programming language, and how by using Ruby's dangerous flexibility you can manage to warp it towards your needs.
After learning more languages, Ruby is starting to become pretty ugly to me, but somehow people keep managing to ignore all its faults, make little hacks like these, and be very productive with it.
When I first saw it, I wondered why anyone would want this irregular little language when they could just use Smalltalk or Scheme. An early rant asked why I have to know the difference between a block and a Proc: why the &^(%*)(& do I have to know when to use a block, when to use a Proc, and how to convert between them???
http://blog.rubyenrails.nl/articles/category/daily_method
Here we create a to_proc method for Hash: http://blog.rubyenrails.nl/articles/2008/02/26/a-hash-is-a-f...
A Ruby block is always associated with a method, and cannot be captured in a variable without converting it back into a proc. This is done by 'removing' the '&'
def return_block &block
return block
endI'm not saying that you should choose your language based solely on the size of it's community (otherwise I would be pulling my hair out with Java) but the advanced features of Ruby, the expressiveness, and the community together make it a great place to be as a programmer.
In real life, the answer is to know some math and realize that 1 + ... + n = n(n+1)/2, so the entire thing is pointless anyway.
(And if you want to add methods to a given class ad-hoc, you can do it statically with extension methods; Sum is an extension method.)
If not, please downmod it, I have failed.
At the risk of getting even more downmods for saying true things here, can I just point out that it's a little arrogant to pretend that a blog post about Ruby is going to move someone towards self-actualization?
Anyway, have you failed? No. You wanted to show us your favorite line of Ruby code, and you did.
As for me, I don't really have a favorite "one line" of code, but I fondly remember when I was a kid typing in Nibble Magazine's "one and two-liner" programs. Actually, the "lines" were lines as defined by the Apple II's command line buffer limit. Here's an example:
http://www.apple2.org.za/mirrors/ground.icaen.uiowa.edu/appl...
Maybe I'm not a sufficiently abstract person. My favorite two lines of code was an honest-to-god graphical car driving program in two lines of APPLESOFT BASIC [1]. Two lines of code in a language so crappy it's basically a joke. And yet...a full-on-graphical-car-racing program. I'm strongly tempted to think that APPLESOFT BASIC is superior to Ruby, based on the evidence I've seen.
Point is: The next time you show a feature of a langauge, maybe make it solve a problem, or create something real, rather than just showing how few characters it takes to do something banal. Adding numbers together? Seriously, it's a solved problem.
[1] Sorry for the capital letters, but I'm in Apple mode now:
Actually, I wanted to discuss how Ruby's open classes promote language innovation from the fringe, not to try to impress you with how clever that line of code is.
"The next time you show a feature of a langauge, maybe make it solve a problem, or create something real, rather than just showing how few characters it takes to do something banal."
And there you have why my article failed you: you think it is about how useful that line of code is, or how clever it is, or what problem it solves, when I think it is an example of how Ruby is different from centrally planned language.
Is it great code? Of course not. Symbol#to_proc may even be an evolutionary dead end, AFAICT it's just a way to make OO code pretend that it's functional code.
Your criticisms point out that I need to work harder on establishing and communicating my theses, thank you.
A digital-typewriter user will laugh at a PC user if all he sees the PC user doing is word processing.
The article does not claim that (1..100).inject(&:+) is great. It claims that it is a totemic example of Ruby code.
There is nothing that technique X can do that technique Y cannot do given that X and Y are both Turing Equivalent. Of course you can write a library function to sum numbers. Do you also need a library function for the product of numbers?
If so, you now know of a salient difference between the two approaches. One needs a function for each thing you want to do, the other gives you some pieces you combine in different ways to do what you want. Is one better than the other? That's up to you to decide, you are the programmer. Ruby lets you write your program either way.
Now, Symbol#to_proc doesn't, in my opinion, add what I would call power. That's because you can always use a block or a lambda wherever you would use a symbol. But I may not have written the article well: the powerful and dangerous feature in Ruby is not Symbol#to_proc, it's Open Classes. Symbol#to_proc is an example of something you can do with an Open Class. Something else you can do with an Open Class is Hash#to_proc. Something else is Object#andand, a low-rent version of the Maybe Monad in Haskell.
I consider Open Classes to be powerful and dangerous. Am I advocating them? Of course not, it is up to you to decide whether they are a good idea or not. What I find interesting about them is that Rubyists are pushing the language in new directions with them, like Symbol#to_proc. The idea of a language growing from the fringe is also powerful and dangerous. The fringe is an uneducated, seething mass.
Did you even read his article? The whole point was "Symbol#to_proc is a litmus test for how you view programming languages. I like it. What do you think of it?"
Say there exists a class called Errors in some Ruby library. It doesn't have an each() method, but I'd like it to. Nobody would complain if I wrote a function each_error() which took an Errors object as an argument. Reopening the Errors class and giving it an each() method is the way you do that in Ruby, and it's not really any more dangerous.
And on the "technically, could it happen?" side, sure, it could. You can also write a Java library that, in weird cases, could screw up other Java libraries, but the Java folks (even as much as they love to try to keep you safe) don't care, either.
Besides, "each" is quite standard in Ruby. Defining it to mean something other than "call the proc with each element, in order" would be weirdbad, like a C++ programmer defining operator+ to mean subtraction. If you do something weirdbad like that, your library deserves to lose.
ALL OF THE REAL INNOVATION IN SOFTWARE IS RELATED TO THE PROBLEM DOMAIN AND NOT THE LANGUAGE
God, I hope I didn't just rip open the space/time continuum.
;-)
>> (1..100).inject(&:+)
TypeError: wrong argument type Symbol (expected Proc)
from (irb):1
I also am not a fan of doing things a thousand different obscure ways. I like doing things one way, and having that way highly optimized. Typing 10 characters or 20 characters doesn't impact my programming speed, I spend far more time thinking about how to do things the right way.edit:
Ok, did his monkeypatch and it worked. You get 5050. So it is equiv to sum(range(101)) in python, and much less readable. I fail to see why this is a good thing.
Any idea who specifically wrote it initially?
Why what is a good thing? Why that line of code is a good thing? maybe it isn't, maybe arrays need a sum method, maybe you could just write:
(1..100).inject { |acc, n| acc + n }
...and get the same result. But the article has nothing to do with why that line of code is a good thing, it is about the fact that being able to modify the Symbol class in this manner is what makes a langauge like Ruby evolve from the bottom up.
So... do you think that is a good thing? Or a bad thing?
So I am wondering why the author thinks its so fantastic.
As for developing the language, I am usually for flexibility and allowing anything to be modified, however this type of change strikes me as not very useful.
That's entirely the point. If you are in favour of flexibility, you have to accept that people will use it for all sorts of things, not just ones you like.
Anyways, I don't really care, saying anything other than 'I love ruby' is shunned anyways.
Well... I welcome criticism of Ruby. Please say whatever you like in a comment right on the post.
I've never shied away from writing about the things in Ruby that irritate me. How else will we progress if we don't scratch when we have an itch?
For Arc, right now, practically every line is an equivalent.
pg has stated that code brevity is one of the main design goals of arc. But what is pretty obvious is that code brevity is not the only consideration. It is desirable to be able to write very short code, but it should be readable as well. If you write very short code that is difficult for other people to read, that is bad enough. If you write very short code that ends up being difficult even for yourself to read -- then we have a problem.
The above ruby code snippet is a great example of code where reducing the length not only did not reduce readability, but actually increased it. I know some people have complained about it being obfuscated on this board. But to me, and I am sure to a number of other people on this board, it was easy to understand, intuitive even.
so .. in arc, what would be a similar way to create a list of numbers from 1 to 100, and to evaluate the sum of that list?
In Arc, that line would be:
(reduce + (range 1 100))
which is nice, but not much different from Scheme. Pretty readable.Prepending an ampersand before the last argument of a method call means that argument should be converted into a Proc and sent as a callback block to that method.