Some useful closures, in Ruby
Posted by Eric Kidd Thu, 01 Feb 2007 23:36:00 GMT
Reginald Braithwaite has just posted a short introduction to closures in Ruby. Closures allow you to pass functions around your program, and build new functions from old ones.
Programming languages that support closures include Perl, Ruby, Python (sorta), Lisp, Haskell, Dylan, Javascript and many others.
The Dylan programming language included four very useful functions built using closures: complement, conjoin, disjoin and compose. The names are a bit obscure, but they can each be written in a few lines of Ruby.
Let’s start with complement:
# Builds a function that returns true
# when 'f' returns false, and vice versa.
def complement f
lambda {|*args| not f.call(*args) }
endWe can use this to build the “opposite” of a function:
is_even = lambda {|n| n % 2 == 0 }
is_odd = complement(is_even)
is_odd.call(1) # true
is_odd.call(2) # falsecompose is another useful function:
# Builds a function which calls 'f' with
# the return value of 'g'.
def compose f, g
lambda {|*args| f.call(g.call(*args)) }
endWe can use this to pass the output of one function to the input of another:
mult2 = lambda {|n| n*2 }
add1 = lambda {|n| n+1 }
mult2_add1 = compose(add1, mult2)
mult2_add1.call(3) # 7The conjoin function is a bit more complicated, but still very useful:
# Builds a function which returns true
# whenever _every_ function in 'predicates'
# returns true.
def conjoin *predicates
base = lambda {|*args| true }
predicates.inject(base) do |built, pred|
lambda do |*args|
built.call(*args) && pred.call(*args)
end
end
endWe can use it to construct the logical “and” of a list of functions:
is_number = lambda {|n| n.kind_of?(Numeric) }
is_even_number = conjoin(is_number, is_even)
is_even_number.call("a") # false
is_even_number.call(1) # false
is_even_number.call(2) # trueThe opposite of conjoin is disjoin:
# Builds a function which returns true
# whenever _any_ function in 'predicates'
# returns true.
def disjoin *predicates
base = lambda {|*args| false }
predicates.inject(base) do |built, pred|
lambda do |*args|
built.call(*args) || pred.call(*args)
end
end
endThis allows us to construct the logical “or” of a list of functions:
is_string = lambda {|n| n.kind_of?(String) }
is_string_or_number =
disjoin(is_string, is_number)
is_string_or_number.call("a") # true
is_string_or_number.call(1) # true
is_string_or_number.call(:a) # falseThese were four of the first closure-related functions I ever used, and they’re still favorites today.
Feel free to post versions in other languages below!
