Some useful closures, in Ruby
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) }
end
We 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) # false
compose 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)) }
end
We 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) # 7
The 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
end
We 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) # true
The 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
end
This 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) # false
These 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!
Want to contact me about this article? Or if you're looking for something else to read, here's a list of popular posts.
conjoin
anddisjoin
a bit if you are willing to throw out the return values that generated the exit case and just throw back True or False.*args,&blk
every time you accept and propagate the arguments. For compose you'll needconjoin
and&
, so you could have