Live data from Hacker News

(1..100).inject(&:+)

weblog.raganwald.com

31–40 of 66 posts

Re: (1..100).inject(&:+)

#31
To some degree, using open classes is just how you write functions in Ruby.

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.

Re: (1..100).inject(&:+)

#32
post #14

The VB.NET equivalent is Enumerable.Range(1, 100).Sum, which seems clearer to me. Why is this so impressive? If Visual Basic comes close to your beloved code snippet, it's probably not that big of a deal. 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…

Replace + in the Ruby with multiplication, or division, or boolean and, or even exponentiation, and show me the VB equivalent.

A digital-typewriter user will laugh at a PC user if all he sees the PC user doing is word processing.

Re: (1..100).inject(&:+)

#33
post #6

Anyone want to explain that code to someone who doesn't know Ruby?

The way to write this in ruby without extending the symbol class is

  (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.

Re: (1..100).inject(&:+)

#34
post #6

Anyone want to explain that code to someone who doesn't know Ruby?

The way to write this in ruby without extending the symbol class is (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…

"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???

Re: (1..100).inject(&:+)

#35
That sort of thing, for all of its doubtless glories, represents nothing so much as a contempt of the next programmer who has to deal with it. We're just moving bits and bytes around here, people. Please sum up the numbers and don't introduce any mysteries into the plumbing.

ALL OF THE REAL INNOVATION IN SOFTWARE IS RELATED TO THE PROBLEM DOMAIN AND NOT THE LANGUAGE

Re: (1..100).inject(&:+)

#36
post #16

Earlier quoted context omitted.

The same code in k: +/!100 4950 Or if you insist on 1-indexing: +/1+!100 5050

What does '/' mean? Also, why does '+' seem to do different things in the first and second expressions? I suppose '!n' means "array of integers ending at n" which seems like an odd choice since it's neither 'not' nor factorial.

'/' in this case is the adverb 'over'. When applied to a function it causes that function to fold over a list. This is the same as inject as far as I know.

You 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)

Re: (1..100).inject(&:+)

#37

That sort of thing, for all of its doubtless glories, represents nothing so much as a contempt of the next programmer who has to deal with it. We're just moving bits and bytes around here, people. Please sum up the numbers and don't introduce any mysteries into the plumbing. ALL OF THE REAL INNOVATION IN SOFTWARE IS RELATED TO THE PROBLEM DOMAIN AND NOT THE LANGUAGE

If you're saying something that's actually true, you don't need to use all uppercase.

Re: (1..100).inject(&:+)

#38
post #16

Earlier quoted context omitted.

The same code in k: +/!100 4950 Or if you insist on 1-indexing: +/1+!100 5050

What does '/' mean? Also, why does '+' seem to do different things in the first and second expressions? I suppose '!n' means "array of integers ending at n" which seems like an odd choice since it's neither 'not' nor factorial.

[deleted]

Re: (1..100).inject(&:+)

#39
post #37

That sort of thing, for all of its doubtless glories, represents nothing so much as a contempt of the next programmer who has to deal with it. We're just moving bits and bytes around here, people. Please sum up the numbers and don't introduce any mysteries into the plumbing. ALL OF THE REAL INNOVATION IN SOFTWARE IS RELATED TO THE PROBLEM DOMAIN AND NOT THE LANGUAGE

If you're saying something that's actually true, you don't need to use all uppercase.

ONE PLUS ONE EQUALS TWO.

God, I hope I didn't just rip open the space/time continuum.

Re: (1..100).inject(&:+)

#40
I use Symbol#to_proc every day. I've never cared for the term "inject", though (or Python's "reduce", for that matter); I find SICP's "accumulate" much more mnemonic.

For what it's worth,

(1..100).to_a.sum

works in Rails, though

(1..100).sum

doesn't.

Post reply on HN