One of the downsides of spending a good deal of time exploring functional programming is that you get to the point where you don't like this sort of thing much any more:
print ","; @method_names.each { | name | print name + "," }; print "\n"
Well, okay... upside, downside.. I'm not sure.
The issue with this code is that it mixes printing, iteration, and formatting. It such a small snippet, it's no big deal but, if we're game we can move to a functional style, peel off at least one of these responsibilities and push it off to someone else.
The trick is to use Map/Reduce. Wait.. no.. stop.. I'm not talking about pulling out a Hadoop-like framework for a simple printing task. I'm talking about the pattern. How about this?
We can replace each with map and then use reduce to build up our result:
puts "," + @method_names.map { | name | name + "," }.reduce(:+)
The map method distributes our work, and the reduce method collects the results.
Map/Reduce: it's not just for data centers any more.
Sidenote: Haskell has a nice function called intersperse which takes an element and a list and produces a new list with the element interspersed. It's easy enough to write, but then I wouldn't get to talk about mapping and reducing.
I can't help but reply with Ruby's puts ',' + @method_names*',' where the map and reduce are replaced by Ruby's join (*',')?
Posted by: Bil_kleb | April 10, 2011 at 11:36 AM
FWIW, something such as @method_names.map(&:name).join(",") would be slightly more idiomatic Ruby.
Posted by: Simon Harris | April 10, 2011 at 12:51 PM
'intersperse' sounds exactly like Clojure's 'interpose'
Posted by: Stefan Tilkov | April 10, 2011 at 01:51 PM
Simon: name is not a method, this code is as simple as ",#{@method_names.join(',')}\n".
I guess I'm trying to solve the combination of printing, iterating, and formatting by just using the appropriate String code to do all of it.
(Side node, the two examples in the blogs do different things; the second lacks the trailing newline.)
Posted by: Peter Harkins | April 10, 2011 at 03:16 PM
Sheesh.. try to use a simple example of a general idea :) Simon: example made the switch from print to puts so the newline is covered.
Posted by: Michael Feathers | April 10, 2011 at 04:49 PM
Michael: Map/reduce, and FP in general, works well in the micro. But in the macro, I still prefer objects. Here's my Haskell translation: (map (\x -> x++",") xs) |> foldr (++) ""
Posted by: Zychr | April 10, 2011 at 07:39 PM
Didn't know that reduce and inject were synonyms. But of course they are. I think Bil's example is interesting and didn't know that join and * were the same thing for strings. Not sure it's a good idea that they are, because it's really obscure. I'd rather use join anyway, because it does what it says on the tin, * implies some kind of array product.
Thanks for introducing me to reduce, it's much easier to understand as 'reduce' even though it's the same method.
Posted by: Fjfish | April 11, 2011 at 05:44 AM
Ferragamo outlet online store has wonderful accessories. Salvatore ferragamo handbags and ferragamo sunglasses are hot sale over the world.
Posted by: Karen millen | December 21, 2011 at 01:00 AM
will this method a good way to solve this.
Posted by: iPhone contacts backup | February 09, 2012 at 11:48 PM