On Wed, Sep 12, 2012 at 11:46 PM, 7stud -- <lists@ruby-forum.com> wrote:
> Just forget inject() even exists. It's really quite a pathetic method.
What do you mean by that?
-Dave
on 2012-09-13 20:31
on 2012-09-14 05:00
Dave Aronson <rubytalk2dave@davearonson.com> wrote: > On Wed, Sep 12, 2012 at 11:46 PM, 7stud -- <lists@ruby-forum.com> wrote: > > > Just forget inject() even exists. It's really quite a pathetic method. > > What do you mean by that? He probably just doesn't grasp how fundamental it is. After all, no one would call "join" pathetic, but it is simply a special case of inject. Or, to put it a better way, inject abstracts intuitively obvious notions such as join, sum, and product. And in Ruby 1.9.3 it gets even cooler, since you can just say: [1,2,3].inject(:+) Not everyone knows LISP or has read The Structure and Interpretation of Computer Programs. Those who have, know. m.
on 2012-09-14 05:25
Agree. #inject is essential for Array. On Sep 14, 2012, at 11:00 AM, Matt Neuburg wrote: > Or, to put it a better way, inject abstracts intuitively obvious notions > A fool + a tool + an autorelease pool = cool! > AppleScript: the Definitive Guide - Second Edition! > http://www.tidbits.com/matt/default.html#applescriptthings > > Best regards, Zhi-Qiang Lei zhiqiang.lei@gmail.com
on 2012-09-14 11:46
On Thu, Sep 13, 2012 at 10:00 PM, Matt Neuburg <matt@tidbits.com> wrote: > Or, to put it a better way, inject abstracts intuitively obvious notions > such as join, sum, and product. And in Ruby 1.9.3 it gets even cooler, > since you can just say: > > [1,2,3].inject(:+) > > I disagree. Nearly everything you want to use inject for, each_with_object is better. Array#join, for example is better implemented using each_with_object than inject strings.each_with_object("") { |current, joined| joined << current } Perhaps in a language like Haskell where strings are just lists of characters, then you could join them in a single pass, if you started at the end and worked backwards. Or perhaps the thunk could be smart enough to compose or allow access to it without creating all the intermediate forms. But in Ruby strings.inject("") { |joined, current| joined + current } is slow and wasteful because it created all the intermediate forms: "", "a", "ab", "abc", "abcd", "abcde" Whereas each_with_object only creates: "abcde" Your example is compelling to you, because you're enamored with the implementation, but `[1,2,3].inject(:+)` is ugly, confusing, and buggy. If we could say something like `[1,2,3].sum_from 0`, this would be clearer because we don't care about the implementation. When we see `.inject(:+)` we have to mentally translate it "oh, we're getting the sum". That cost adds up, things like this should be declarative. It's buggy because if your array is empty, you get `[].inject(:+) # => nil`, but the null object for a sum is 0, so you have to remember to pass the initial argument `[].inject(0, :+) # => 0` (that param should probably be required). It's further ugly because it breaks from Ruby conventions. When you have a method that takes a block, everywhere else you would have to say `[].inject(0, &:+)`, but here, translating the symbol into a block is moved into the method, causing you to think you have a bug until you go read the docs enough times to remember this one-off case. And in the few cases where inject does make more sense than each_with_object, it may be clearer to just iterate over the array with #each, and update a local variable. > Not everyone knows LISP or has read The Structure and Interpretation of > Computer Programs. Those who have, know. m. > > I generally like Lisp, but the elitism around it is just obnoxious, as in this quote (at least for Common Lisp and Scheme, Clojure seems more down to earth).
on 2012-09-14 12:20
On Fri, Sep 14, 2012 at 5:46 PM, Josh Cheek <josh.cheek@gmail.com> wrote: > strings.inject("") { |joined, current| joined + current } > > is slow and wasteful because it created all the intermediate forms: "", "a", > "ab", "abc", "abcd", "abcde" but josh, isn't that because of String#+ ? there is always String#<< or String#concat. nonetheless, am also a fan of inject syntax, and hope to see someday, a more super fast version of inject. The inject syntax is stupidly generic/flexible, that is why many luv it, including me ;-) btw, i usually use each.with_object instead of each_with_object. And i alias with_object to using_object. but hey, that is just me. but regardless, we all are fan of ruby, right? to each, his each, i guess ;-) kind regards -botp
on 2012-09-14 13:07
On Fri, Sep 14, 2012 at 5:19 AM, botp <botpena@gmail.com> wrote: > On Fri, Sep 14, 2012 at 5:46 PM, Josh Cheek <josh.cheek@gmail.com> wrote: > > strings.inject("") { |joined, current| joined + current } > > > > is slow and wasteful because it created all the intermediate forms: "", > "a", > > "ab", "abc", "abcd", "abcde" > > but josh, isn't that because of String#+ ? > > Yes > there is always String#<< or String#concat. > > You're right, since String#<< returns self, you can do it efficiently with inject: [*'a'..'e'].inject('', :<<) # => "abcde" Instead of [*'a'..'e'].inject('', :+) # => "abcde" It deviates from the more functional ideas of immutable data, which is where inject makes the most sense, but in Ruby this case will work sufficiently. When return values don't match up nicely like this, it gets cumbersome (you have to go to multiple lines or use semicolons): %w[a b a c].inject(Hash.new 0) { |sums, char| sums[char] += 1; sums } %w[a b a c].each_with_object(Hash.new 0) { |char, sums| sums[char] += 1 } > btw, i usually use each.with_object instead of each_with_object. And i > alias with_object to using_object. but hey, that is just me. but > regardless, we all are fan of ruby, right? to each, his each, i guess > ;-) > > I only do .with_object when I'm working with an arbitrary enumerator, because I expect it has overhead associated with its laziness. I don't know how it is implemented (it takes a lot of effort for me to figure out what C Ruby is doing), but I think of it basically like this: List = Struct.new :element, :child do def each_with_object(object, &block) block[element, object] child && child.each_with_object(object, &block) object end def each(&block) return LazyIteration.new self, :each unless block block[element] child && child.each(&block) end LazyIteration = Struct.new :target, :message do def with_object(object, &block) target.send(message) { |element| block[element, object] } object end end end list = List.new('a', List.new('b', List.new('c', nil))) list.each_with_object('') { |element, aggregate| aggregate << element } # => "abc" list.each.with_object('') { |element, aggregate| aggregate << element } # => "abc"
on 2012-09-14 22:40
Josh Cheek wrote in post #1075977: > But in Ruby > > strings.inject("") { |joined, current| joined + current } > > is slow and wasteful because it created all the intermediate forms: "", > "a", "ab", "abc", "abcd", "abcde" > Whereas each_with_object only creates: "abcde" Correct, in ruby, because ruby isn't optimised for funtional use. Another example is that there is no tail-recursion unless you build ruby with a special compile-time option. But in other languages, what you've written is actually efficient. For example, Erlang has a specific optimisation for binaries which are appended to, where no reference remains to the previous incarnation of the binary. > Your example is compelling to you, because you're enamored with the > implementation I'd say the opposite; in ruby the implementation is not so good, but it's the concept, the abstraction, which is attractive. foo.each => do something for each element of an array foo.inject => calculate a summary value across all elements of an array In fully functional languages, foo.each makes no sense because "do something" makes no sense - functions don't have side-effects. (Erlang is *not* such a language, by the way, but is part way because it doesn't have mutable variables).
on 2012-09-16 06:42
> Correct, in ruby, because ruby isn't optimised for funtional use. > Interesting. Will it be? Best regards, Zhi-Qiang Lei zhiqiang.lei@gmail.com
on 2012-09-16 10:00
On 16 September 2012 14:41, Zhi-Qiang Lei <zhiqiang.lei@gmail.com> wrote: > > Correct, in ruby, because ruby isn't optimised for funtional use. > > Interesting. Will it be? > I strongly doubt it, there's too much OO in the core for the language to ever lean very far in a stateless (functional) direction. -- Matthew Kerwin, B.Sc (CompSci) (Hons) http://matthew.kerwin.net.au/ ABN: 59-013-727-651 "You'll never find a programming language that frees you from the burden of clarifying your ideas." - xkcd
on 2012-09-16 19:19
On Sun, Sep 16, 2012 at 1:00 AM, Matthew Kerwin <matthew@kerwin.net.au>wrote: > I strongly doubt it, there's too much OO in the core for the language > to ever lean very far in a stateless (functional) direction. FP and OO are not orthogonal. Perhaps the word you were looking for was "mutation"
Please log in before posting. Registration is free and takes only a minute.
Existing account
(Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
Log in with Google account | Log in with Yahoo account
No account? Register here.