views:

124

answers:

4

Hi, I'm looking for examples of functional code in ruby. Maybe you know some gems, where I can find such a code?

+4  A: 

Have you looked at Enumerable?

(1..100).select { |i| i % 5 == 0 }.map { |i| i * 5 }.take(3) #=> [25, 50, 75]
banister
+2  A: 

You might be interested in the talk "Better Ruby through Functional Programming" by Dean Wampler, it shows how to use a FP style with Ruby:

http://vimeo.com/6701329

There's also "Thinking functionally in Ruby" by Tom Stuart:

http://skillsmatter.com/podcast/ajax-ria/enumerators

Michael Kohl
+1  A: 

A couple of months ago, I wondered whether it was possible to make a mixin that behaves exactly like Enumerable, but is based on folding instead of enumerating. Or more precisely, I already knew that it was possible to do this, since fold is a generic iteration operation that is equal in expressive power to foreach, but I wanted to know what it would look like and how hard it would be.

I got bored after I had implemented most methods up to the letter g, so it's incomplete. Also, the version I show here is simplified, since making it behave exactly like Enumerable is a PITA in Ruby. (For example, there are overloaded methods in there, but Ruby doesn't support overloading. This isn't a problem for most Ruby implementations, because they implement Enumerable in Java or C# or other languages that do support overloading, but it is pretty painful when doing it in pure Ruby, so I decided to leave it out.)

Enumerable is full of higher-order procedures, and of course fold (or reduce / inject as it is called in Ruby) is itself a higher-order procedure, so this code is full of them.

module Enumerable
  def all?
    reduce(true) {|res, el| res && yield(el) }
  end

  def any?
    reduce(false) {|res, el| res || yield(el) }
  end

  def collect
    reduce([]) {|res, el| res + yield(el) }
  end
  alias_method :map, :collect

  def count
    reduce(0) {|res, el| res + 1 if yield el }
  end

  def detect
    reduce(nil) {|res, el| if yield el then el end unless res }
  end
  alias_method :find, :detect

  def drop(n=1)
    reduce([]) {|res, el| res.tap {|res| res + el unless n -= 1 >= 0 }}
  end

  def each
    reduce(nil) {|_, el| yield el }
  end

  def each_with_index
    reduce(-1) {|i, el| (i+1).tap {|i| yield el, i }}
  end

  def find_all
    reduce([]) {|res, el| res.tap {|res| res + el if yield el }}
  end
  alias_method :select, :find_all

  def grep(pattern)
    reduce([]) {|res, el| res.tap {|res| res + yield(el) if pattern === el }}
  end

  def group_by
    reduce(Hash.new {|hsh, key| hsh[key] = [] }) {|res, el| res.tap {|res|
        res[yield el] << el
    }}
  end

  def include?(obj)
    reduce(false) {|res, el| break true if res || el == obj }
  end

  def reject
    reduce([]) {|res, el| res.tap {|res| res + el unless yield el }}
  end
end

You will notice that I use side-effects in some places. I could have written it without side-effects instead, but it would have been much more complicated. And the problem is that there is no way for me to ensure that the reduce method, which is provided by the client of the mixin, or any of the methods from the core library, don't have side-effects.

Another nice example is the Prelude library for Ruby, which is an implementation of some parts of the Haskell Prelude (Haskell's equivalent to Ruby's core library) in Ruby.

Jörg W Mittag
A: 

"The Ruby Programming Language" has half a chapter where they work on a couple of additions to enumerable to make ruby look like Haskell.

You may also want to browse previous Stack Overflow questions tagged with both "Ruby" and "functional-programming" here.

Andrew Grimm