Functional programming

Brian Candler wrote:

Haris Bogdanovic wrote:

I know Ruby programming well but I wanted to add funtional paradigm in
my
programming as it is very usefull.

If you know Ruby well - and you obviously understand functional
programming, because you know it is "usefull" (sic) - then just start
writing functional programs. To do this, make sure that:

1. you don't modify any objects. Only use methods which return new
objects.

2. once a local variable is assigned, you don't reassign it.

However Ruby won't enforce (1) unless you litter your code with 'freeze'
statements, and it can't enforce (2) at all.

Well then ... just as "it's possible to write FORTRAN programs in any
language", it's *possible* to write "functional" programs in any
language. But as you point out, a pure functional style "goes against
the grain" in Ruby, if it doesn't or can't enforce (or even diagnose)
"non-functional" code.

Programming is as much, or more, about communication among the
programmers and between the programmers and the users as it is about
communication between the programmers and the "machine." So if you have
to spend time saying, "this is functional code", you've already lost
something, and introduced opportunities for mis-translation.

In short, I suspect that a more practical solution might be a language
that has object orientation and functional coding styles both baked in
right from the start. I'm not an expert on all the dozens of "obscure"
languages out there, so I can't give any names. But I know they exist.

Go and look at Erlang. Massive real-world systems are built out of this,
with incredible reliability, using only functional programming and CSP.
It's also very straightforward to pick up and use, and has a very
comprehensive standard library.

Remember also that functional languages allow all sorts of compile-time
optimisations which are impossible in Ruby, so there is the potential
for much higher performance. For example, OCaml generates code which is
reputedly only half the speed of the equivalent C code.

Did you mean "twice the speed?" Is OCaml faster or slower than C? And why?

I meant, every expression is an object. Not sure that's the case with clisp.

"Pascal J. Bourguignon" <pjb@informatimago.com> wrote in message
news:87hc48bsgp.fsf@informatimago.com...

···

"Haris Bogdanovic" <fbogdanovic@xnet.hr> writes:

In Ruby everything is an object. That's my favourite Ruby's feature. And
you
showed that by just making one module you can have Lisp like functional
programming. So I'll stick with Ruby.

In Lisp too, everything is an object. But there are several kinds of
objects, and you can create your own kinds too (you can write new
meta-classes in CLOS).

C/USER[15]> (defclass automobile () ())
#1=#<STANDARD-CLASS AUTOMOBILE>
C/USER[16]> (defvar *car* (make-instance 'automobile))
*CAR*
C/USER[17]> (class-of *car*)
#1=#<STANDARD-CLASS AUTOMOBILE>
C/USER[18]> (class-of 1)
#1=#<BUILT-IN-CLASS INTEGER>
C/USER[19]> (class-of "string")
#1=#<BUILT-IN-CLASS STRING>
C/USER[20]> (defstruct wheel)
WHEEL
C/USER[21]> (defclass automobile () ((wheels :accessor wheels :initform
(list (make-wheel) (make-wheel) (make-wheel) (make-wheel)))))
WARNING: DEFCLASS: Class AUTOMOBILE (or one of its ancestors) is being
redefined, instances are obsolete
#1=#<STANDARD-CLASS AUTOMOBILE :VERSION 1>
C/USER[22]> (wheels *car*)
(#S(WHEEL) #S(WHEEL) #S(WHEEL) #S(WHEEL))
C/USER[23]> (class-of (wheels *car*))
#1=#<BUILT-IN-CLASS CONS>
C/USER[24]> (class-of (first (wheels *car*)))
#1=#<STRUCTURE-CLASS WHEEL>
C/USER[25]>

--
__Pascal Bourguignon__

Only the bits of a program that are appropriate for that.
I don't know how can a Haskell programmer live without objects in larger
projects ? You loose track of what is where in the program.

"andrea" <kerny404@gmail.com> wrote in message
news:c3f4685a-6558-4a75-93f0-a6b1c9061c63@n33g2000pri.googlegroups.com...

···

Very interesting discussion, I love ruby and I love also haskell,
which I think made me a better programmer.

But does it really make sense to program in a functional way in ruby??

"Functional" code can be much more clean and elegant (in my opinion)
but what about performance issues???

The interpreter is going to have many new objects created around, and
so there will be more work for the garbage collector or more memory
used, am I wrong?

That's a great question.

Functional languages have been a hot topic lately and it seems with that comes the need to make all languages functional. We've seen plenty of that in Rubyland. Try to count the number of actor style networking libraries (heavily inspired by Erlang I'm guessing) we have now.

But you've nailed the key question: is this right for Ruby? My feeling is probably not.

Don't get me wrong. I like functional languages. I've learned a lot from using them even just a little. I think there are projects where I would prefer them.

However, Ruby is almost a flat opposite to them in many ways. Ruby loves side effects and data is just about never locked down in Ruby. That's not bad, it's just Ruby.

There may be times when we should adopt a functional approach here and there. but if you are trying to avoid calling standard iterators in Ruby because they aren't functional, you're trading Ruby advantages away for heavy Ruby minuses. Performance is just one example of this. If you are willing to make that trade, why not trade languages and get back to the things you want being an advantage?

Of course, that's all just my opinion. I mean no offense.

James Edward Gray II

···

On Jan 9, 2009, at 6:39 AM, andrea wrote:

But does it really make sense to program in a functional way in ruby??

andrea <kerny404@gmail.com> writes:

Very interesting discussion, I love ruby and I love also haskell,
which I think made me a better programmer.

But does it really make sense to program in a functional way in ruby??

"Functional" code can be much more clean and elegant (in my opinion)
but what about performance issues???

The interpreter is going to have many new objects created around, and
so there will be more work for the garbage collector or more memory
used, am I wrong?

Who cares about processing time? The processors are faster and faster
by the minute. Memory and memory is bigger by the hour.

But programmer's time is still incompressible. I still have only 24
hours per day. This is the time that should be optimized. And if
writting functional code makes us programmers spare development and
debugging time, so be it.

Of course, if ruby is not good at optimizing functional code, and this
posed any performance problem in the deployed applications, you would
better switch to Common Lisp or Haskell.

···

--
__Pascal Bourguignon__

Brian Candler wrote:

# Example: convert all hash keys to strings
src = {:one=>1, :two=>2}

# Imperative
out = src.inject({}) { |h,(k,v)| h[k.to_s] = v; h }

# Functional
out = src.inject({}) { |h,(k,v)| h.merge(k.to_s => v) }

src = {:one,1, :two,2}
    ==>{:one=>1, :two=>2}
Hash[ *src.map{|k,v| [k.to_s,v]}.flatten ]
    ==>{"two"=>2, "one"=>1}

Haris Bogdanovic wrote:

I would like if this sort could be made of Ruby functions;
inject,select, detect, reject, collect, not with "module" you
implemented. And it doesnt't have to be a list sorting; can be an
array sorting or something. I'm not an expert in knowing all
differences between all kinds of collections. And what about
recursion ? If I want to sort an array do I have to use recursion and
how ? There are tutorials on functional programming in general but
not with Ruby. Does anybody maybe has some link to something similar ?

"Pascal J. Bourguignon" <pjb@informatimago.com> wrote in message
news:87d4ewbrgz.fsf@informatimago.com... >"Haris Bogdanovic"
<fbogdanovic@xnet.hr> writes:
>
> > I managed to find a minimum:
> >
> > [1,6,4,7,8].inject {|a,b| if a < b then a else b end}
> >
> > but I can't still find a way to sort list (functional way and not
> > with existing sort method)
>
>
> One difficulty is that vectors are difficult to handle with purely
> functional programming: you cannot modify them, not a single slot;
> when you want to change just one slot of a vector, in purely
> functionnal programming, you have to define a whole new vector,
> that contains the same elements as the old vector, but for the one
> that is "changed".
>
> But you asked first for lists, and I showed you how to implement
> lists. So now it should be easy to implement a functionnal sort
> algorithm working on lists.
>
> For an exemple here is a simple merge sort. We need a function to
> merge two lists:
>
> (def mergelist(list1,list2,lessp)
> (if (endp list1)
> list2
> elsif (endp list2)
> list1
> elsif (funcall lessp,(first list1),(first list2))
> (cons (first list1),(mergelist (rest list1),list2,lessp))
> else
> (cons (first list2),(mergelist list1,(rest list2),lessp))
> end)
> end)
>
>
> irb(main):545:0>
> (begin
> (terpri)
> (printlist (mergelist (list 1,3,5,7,8,9,11),(list
> 2,4,6,10,11,12,13),(method :<))) (terpri)
> end)
>
> (1 2 3 4 5 6 7 8 9 10 11 11 12 13)
> nil
>
>
>
> Then a function to split a list into two parts separated by a pivot
> (one list containing all the elements smaller-or-equal to the
> pivot, and the other all the elements greater than the pivot):
>
> (def values(*values)
> values
> end)
>
>
> (def splitlistinternal(list,pivot,lessp,less,more)
> (if (endp list)
> (values less,more)
> elsif (funcall lessp,pivot,(first list))
> (splitlistinternal (rest list),pivot,lessp,less,(cons (first
> list),more)) else
> (splitlistinternal (rest list),pivot,lessp,(cons (first
> list),less),more) end)
> end)
>
> (def splitlist(list,pivot,lessp)
> (splitlistinternal list,pivot,lessp,nil,nil)
> end)
>
>
> (def valuelist(values)
> (list *values)
> end)
>
>
>
> irb(main):604:0>
> (begin
> (terpri)
> (printlist (valuelist (splitlist (list 1,2,3,4,5,6,7),3,(method
> :<)))) (terpri)
> end)
>
> ((3 2 1) (7 6 5 4))
> nil
>
>
> With these two utilities, writting a functional merge sort is
> trivial:
>
> (def sortlist(list,lessp)
> (if ((endp list) or (endp (rest list)))
> list
> else
> (pivot = (first list))
> (less,more = (splitlist (rest list),pivot,lessp))
> (mergelist (sortlist less,lessp),(cons pivot,(sortlist
> more,lessp)),lessp) end)
> end)
>
>
> irb(main):635:0>
> (begin
> (terpri)
> (printlist (mapcar (lambda{|list|
> (sortlist list,(method :<))
> }),(list (list),(list 1),(list
> 5,4,3,2,1),(list 1,2,3,4,5),(list 1,3,5,4,2),(list 5,3,1,2,4))))
> (terpri) end)
>
> (nil (1) (1 2 3 4 5) (1 2 3 4 5) (1 2 3 4 5) (1 2 3 4 5))
> nil
>
>

Ruby:

def merge list1, list2, &less
  return list1 + list2 if list1.empty? or list2.empty?
  less = ( less or proc{|a,b| a < b} )
  less[ list1[0], list2[0] ] and
    [ list1[0] ] + merge( list1[1..-1], list2, &less ) or
    [ list2[0] ] + merge( list1, list2[1..-1], &less )
end

p merge( [1,3,5], [2,4,6] )
p merge( [-1,-3,-5], [-2,-4,-6] ){|a,b| a > b}

def merge_sort list
  return list if list.size < 2
  half = list.size / 2
  merge merge_sort( list[0...half] ), merge_sort( list[half..-1] )
end

p merge_sort( [9,2,8,5,6,3] )
5.times{|i| p merge_sort( (0..i).to_a.reverse ) }

Yes or let us say you will be wrong very soon :).

Have a look at this to understand why:
http://rubyconf2008.confreaks.com/how-ruby-can-be-fast.html

HTH
Robert

···

On Fri, Jan 9, 2009 at 1:39 PM, andrea <kerny404@gmail.com> wrote:

The interpreter is going to have many new objects created around, and
so there will be more work for the garbage collector or more memory
used, am I wrong?

--
It is change, continuing change, inevitable change, that is the
dominant factor in society today. No sensible decision can be made any
longer without taking into account not only the world as it is, but
the world as it will be ... ~ Isaac Asimov

William James wrote:

utter irrational.

utterly

William James wrote:

Mike Gold wrote:

It's a clever way to get
people accustomed to parens without actually using Lisp. A way-point
on the road to enlightenment.

There you have it. Hierophants of Commune Lisp are utter irrational.
It's a religion to them. In comp.lang.lisp you will find threads
named "How did you discover Lisp?", i.e., "How did you get religion?"

Ironically, a distinguishing characteristic of zealotry is the
inability to recognize waggishness or sarcasm.

There are several clues you could have picked up.

(1) If you are at all familiar with Star Wars, you could have noticed
that I paraphrased Obi-Wan Kenobi in the same post.

(2) Even if you've never heard of Star Wars, the hyperbolic nature of
my post should have been obvious.

(3) If you cared to check whether your assumptions had any merit, you
could have noticed the 40 non-trolling posts I've made to
comp.lang.ruby. No posts to comp.lang.lisp.

(4) I contributed a small patch to Ruby; I appear in the ChangeLog.

On the other hand, your posting history reveals that you persistently
troll comp.lang.lisp with Ruby evangelism, much to the annoyance of
its inhabitants.

  "If you hate a person, you hate something in him that is part of
  yourself. What isn't part of ourselves doesn't disturb us."
    --Herman Hesse

···

--
Posted via http://www.ruby-forum.com/\.

"M. Edward (Ed) Borasky" <znmeb@cesmail.net> writes:

In short, I suspect that a more practical solution might be a language
that has object orientation and functional coding styles both baked in
right from the start. I'm not an expert on all the dozens of "obscure"
languages out there, so I can't give any names. But I know they exist.

Common Lisp.

···

--
__Pascal Bourguignon__

M. Edward (Ed) Borasky wrote:

For example, OCaml generates code which is
reputedly only half the speed of the equivalent C code.

Did you mean "twice the speed?" Is OCaml faster or slower than C? And
why?

I did mean half the speed, i.e. OCaml is slower.

OCaml is a high-level language, but code written in OCaml still manages
to achieve ~50% of the speed of hand-written C. Given that C can be
considered portable machine code, this is a pretty impressive
achievement.

···

--
Posted via http://www.ruby-forum.com/\.

"Haris Bogdanovic" <fbogdanovic@xnet.hr> writes:

"Pascal J. Bourguignon" <pjb@informatimago.com> wrote in message
news:87hc48bsgp.fsf@informatimago.com...

"Haris Bogdanovic" <fbogdanovic@xnet.hr> writes:

In Ruby everything is an object. That's my favourite Ruby's feature. And
you
showed that by just making one module you can have Lisp like functional
programming. So I'll stick with Ruby.

In Lisp too, everything is an object. But there are several kinds of
objects, and you can create your own kinds too (you can write new
meta-classes in CLOS).

I meant, every expression is an object. Not sure that's the case with clisp.

Expressions, in ruby are nothing. Expression in lisp are objects.

The result of evaluating an expresssion The result of evaluating an expression
in ruby is an object. in lisp is an object.

Since expression in ruby are nothing Since expressions in lisp are objects
we stop here. some expressions may return objects
                                         that are other expressions.

                                         Therefore you can write in lisp
                                         program that write programs
                                         (little Santa's helpers), more
                                         easily than you can in ruby.

C/USER[127]> (let ((expression '(+ 1 2)))
                (values (class-of expression)
                        (eval expression)
                        (class-of (eval expression))))
#1=#<BUILT-IN-CLASS CONS> ;
3 ;
#1=#<BUILT-IN-CLASS INTEGER>
C/USER[128]> (let ((expression '(list '+ 1 2)))
                (values (class-of expression)
                        (eval expression)
                        (class-of (eval expression))))
#1=#<BUILT-IN-CLASS CONS> ;
(+ 1 2) ;
#1=#<BUILT-IN-CLASS CONS>
C/USER[129]>

But of course, you can get it only when you become lazy and want to
automate not only a bank teller's job, but yours also.

(Of course, like in any programming language, you can in Ruby put
expressions into strings, and have the interpreter read again these
strings, and you can even use libraries (because it is hard enough
most ruby programmers couldn't do it themselves) to parse ruby text
into ruby objects (Array, Symbol, and other ruby Object), and back
from these R-expr into a string. Oops, you don't get an expression
yet. You have again to feed back the interpreter with this string, to
let it do again the parsing, build the expression in some internal
opaque and inaccessible object (not a ruby object, IIRC ruby is
written in C, that would mean that ruby expressions are actually C
structures, not ruby objects)).

···

--
__Pascal Bourguignon__

Pascal J. Bourguignon wrote:

Of course, if ruby is not good at optimizing functional code, and this
posed any performance problem in the deployed applications, you would
better switch to Common Lisp or Haskell.

Perhaps most importantly, Ruby doesn't optimise tail recursion (although
I think I read somewhere that ruby1.9 can do this, but only if you set a
flag when compiling the interpreter)

It's also true that cons(a,b) is going to be more efficient than [a] +
b, because the latter creates a whole new Array object and copies all
the elements. (This is of benefit primarily for algorithms which
generate new lists by prepending elements to the front of existing
lists)

However if you don't care about this, you can write your functional
algorithms using Ruby's Array as if it were a list.

class Array
  def car
    self[0]
  end
  def cdr
    self[1..-1]
  end
end

If you want though, you can create a true Cons object in Ruby. If you
make it Enumerable then you can keep much of the Ruby goodness in that
area.

class Cons
  include Enumerable
  attr_accessor :car, :cdr
  def initialize(car, cdr = nil)
    @car = car
    @cdr = cdr
  end
  def each(&blk)
    yield @car
    @cdr.each(&blk) if @cdr
  end
  class << self
    alias : :new
  end
end

l = Cons[1, Cons[2, Cons[3]]]
puts l.inject(0) { |acc,v| acc + v }
m = Cons[4, l]
puts m.inject(0) { |acc,v| acc + v }

p l.to_a # using Enumerable#to_a
p m.to_a

You may find this more attractive than going the whole
"lets-pretend-Ruby-is-Lisp" approach. Similarly, I don't really see the
need to define a 'function' again from scratch, when you have lambda
{...} natively.

···

--
Posted via http://www.ruby-forum.com/\.

And Scala (if you like static typing - gasp! ;), OCaml and F# (I believe).

···

On Thu, Jan 8, 2009 at 10:09 AM, Pascal J. Bourguignon <pjb@informatimago.com> wrote:

"M. Edward (Ed) Borasky" <znmeb@cesmail.net> writes:

In short, I suspect that a more practical solution might be a language
that has object orientation and functional coding styles both baked in
right from the start. I'm not an expert on all the dozens of "obscure"
languages out there, so I can't give any names. But I know they exist.

Common Lisp.

--
__Pascal Bourguignon__

--
Dean Wampler
http://www.objectmentor.com
http://www.polyglotprogramming.com
http://www.aspectprogramming.com
http://aquarium.rubyforge.org
http://www.contract4j.org

Brian Candler wrote:

I don't really see the need to define a 'function' again from
scratch, when you have lambda {...} natively.

Pascal was making a simulation of first-class functions in ruby. The
difference between lambda { } and a real first-class function is quite
profound.

When I say that I prefer functional style in ruby, I mean that this

  def sum(array)
    array.inject(0) { |acc, x| acc + x }
  end

is better than this

  def sum(array)
    result = 0
    for x in array
      result += x
    end
    result
  end

In addition, chaining blocks/lambdas can often be terser/better than
the imperative equivalent. When the details of the step-by-step
operations are abstracted, the result is smaller code with less room
for error.

I use functional-ness in ruby on a small scale, such as inside the
implementation of a method, but no wider. For reasons I gave earlier,
functional style is most applicable to flat arrays and hashes, and
probably less so with more complex structures
(http://groups.google.com/group/comp.lang.ruby/browse_thread/thread/472e714cffa0f50c\).

···

--
Posted via http://www.ruby-forum.com/\.

So you want to say that common lisp is pure object oriented like ruby ?.

"Pascal J. Bourguignon" <pjb@informatimago.com> wrote in message
news:7c7i54eaoi.fsf@pbourguignon.anevia.com...

···

"Haris Bogdanovic" <fbogdanovic@xnet.hr> writes:

"Pascal J. Bourguignon" <pjb@informatimago.com> wrote in message
news:87hc48bsgp.fsf@informatimago.com...

"Haris Bogdanovic" <fbogdanovic@xnet.hr> writes:

In Ruby everything is an object. That's my favourite Ruby's feature.
And
you
showed that by just making one module you can have Lisp like functional
programming. So I'll stick with Ruby.

In Lisp too, everything is an object. But there are several kinds of
objects, and you can create your own kinds too (you can write new
meta-classes in CLOS).

I meant, every expression is an object. Not sure that's the case with
clisp.

Expressions, in ruby are nothing. Expression in lisp are objects.

The result of evaluating an expresssion The result of evaluating an
expression
in ruby is an object. in lisp is an object.

Since expression in ruby are nothing Since expressions in lisp are
objects
we stop here. some expressions may return
objects
                                        that are other expressions.

                                        Therefore you can write in lisp
                                        program that write programs
                                        (little Santa's helpers), more
                                        easily than you can in ruby.

C/USER[127]> (let ((expression '(+ 1 2)))
               (values (class-of expression)
                       (eval expression)
                       (class-of (eval expression))))
#1=#<BUILT-IN-CLASS CONS> ;
3 ;
#1=#<BUILT-IN-CLASS INTEGER>
C/USER[128]> (let ((expression '(list '+ 1 2)))
               (values (class-of expression)
                       (eval expression)
                       (class-of (eval expression))))
#1=#<BUILT-IN-CLASS CONS> ;
(+ 1 2) ;
#1=#<BUILT-IN-CLASS CONS>
C/USER[129]>

But of course, you can get it only when you become lazy and want to
automate not only a bank teller's job, but yours also.

(Of course, like in any programming language, you can in Ruby put
expressions into strings, and have the interpreter read again these
strings, and you can even use libraries (because it is hard enough
most ruby programmers couldn't do it themselves) to parse ruby text
into ruby objects (Array, Symbol, and other ruby Object), and back
from these R-expr into a string. Oops, you don't get an expression
yet. You have again to feed back the interpreter with this string, to
let it do again the parsing, build the expression in some internal
opaque and inaccessible object (not a ruby object, IIRC ruby is
written in C, that would mean that ruby expressions are actually C
structures, not ruby objects)).

--
__Pascal Bourguignon__

Brian Candler wrote:

M. Edward (Ed) Borasky wrote:
>> For example, OCaml generates code which is
>> reputedly only half the speed of the equivalent C code.
>
> Did you mean "twice the speed?" Is OCaml faster or slower than C?
> And why?

I did mean half the speed, i.e. OCaml is slower.

OCaml is a high-level language, but code written in OCaml still
manages to achieve ~50% of the speed of hand-written C. Given that C
can be considered portable machine code, this is a pretty impressive
achievement.

Don't take Ed seriously. You will find that he never posts any
Ruby code that he has written.

And he has already been taught that OCaml can be as fast as C:

http://groups.google.com/group/comp.lang.ruby/browse_thread/thread/e2138
1fb5b6a47f6

Mike Gold wrote:

Pascal was making a simulation of first-class functions in ruby. The
difference between lambda { } and a real first-class function is quite
profound.

For the benefit of this duffer, could you briefly explain the
difference? lambdas are "first-class enough" for me: I can pass them as
function arguments, I can return them from functions, and I can create
new instances of them which bind to different environments.

Now, having a look in Wikipedia:

"In computer science, a programming language is said to support
first-class functions (or function literal) if it treats functions as
first-class objects. Specifically, this means that the language supports
constructing new functions during the execution of a program, storing
them in data structures, passing them as arguments to other functions,
and returning them as the values of other functions. This concept
doesn't cover any means external to the language and program
(metaprogramming), such as invoking a compiler or an eval function to
create a new function."

Personally I consider Ruby lambdas to be first-class as they are.

It looks like the definition has been explicitly rigged to exclude
functions created by eval, without really explaining why. But even so, I
can create functions dynamically without eval, which differ by their
binding:

  def make_incrementer(n)
    return lambda { |x| x+n }
  end

Wikipedia continues:

"These features are a necessity for the functional programming style, in
which (for instance) the use of higher-order functions is a standard
practice. A simple example of a higher-ordered function is the map or
mapcar function, which takes as its arguments a function and a list, and
returns the list formed by applying the function to each member of the
list. For a language to support map, it must support passing a function
as an argument."

Of course, Ruby supports the map abstraction, and the passing of
functions (or blocks) to map, quite happily.

Now, map is just a "simple example", and perhaps Ruby supports only a
limited subset of functionality which includes map. Can you provide a
better example which shows how a Ruby lambda is not first-class?

···

--
Posted via http://www.ruby-forum.com/\.

There are two, not-really-identical things that people mean when they
speak of "functional programming" - programming via pure,
side-effectless functions, and programming via higher order functions.
The former doesn't really make sense for ruby, as several people have
pointed out, but the latter is a useful technique, and pretty well
supported.

martin

···

On Sat, Jan 10, 2009 at 5:39 PM, Mike Gold <mike.gold.4433@gmail.com> wrote:

I use functional-ness in ruby on a small scale, such as inside the
implementation of a method, but no wider. For reasons I gave earlier,
functional style is most applicable to flat arrays and hashes, and
probably less so with more complex structures
(http://groups.google.com/group/comp.lang.ruby/browse_thread/thread/472e714cffa0f50c\).