Skip to main content

Passing Functions and Lambdas into Functions with Ruby

Ruby's New Style of Lambda Functions


f = ->( m ) { p m }
f.call( 1 )
#=> 1
Which of course means the same thing as:


f = lambda { |n| p n }
f.call(1)
#=> 1

Ruby Proc Objects


p = Proc.new { |n| p n + 2 }
p.call(2)
#=> 4

Using a Function as a Closure in Ruby


def domo( k )
  ->(m) { p m + k }
end

z = domo( 5 )
z.call( 5 )
#=> 10
Function :domo takes a single parameter. Within :domo, we create a lambda that takes a single parameter, and adds that parameter to the value :domo takes in as its parameter. Then, we assign z to be the result of the lambda in :domo with its 'k' parameter loaded with 5.

When z is called, we pass (another) 5 to it. This parameter loads the lambdas n parameter. The lambda executes, essentially adding n(5) + k(5) and yielding the result of 10.

The thing about closures such as this is, we can load the initial value of the lambda to be whatever we want it to be when assigning the function :domo's return value to z. That becomes a fixed value that z will always have. But..., we can call z with whatever value we wish to add z to. For example:


z = domo(6)
z.call(4)
#=> 10
z.call(6)
#=> 12

etc., etc. That's the power of the closure. You could set up a number of such closures with constant values set up, and then operate on those values with whatever numbers you wish to pass in. Each closure represents its own individual processing with its own loaded value.

Passing Functions to Functions in Ruby


def fritter( f, n )
  func = method( f )
  func.call( :n => n )
end

def mac( opts = {} )
  v = opts[ :n ]
  v + 6
end

p fritter( :mac, 6 )
# => 12

Passing one function to another function as a parameter is how Ruby can be used in a functional programming style. The function :fritter takes the function :mac, as well as a number, as parameters.

Inside :fritter, on the first line, the symbol passed in to parameter f is converted to a method object via the :method function. This method object is stored in the variable, func.
Next, on the second line of :fritter, we call the method object, which is the method, :mac, sending it the parameter 6
To pass a function to another function in Ruby, the name of the function is passed. To name a function, a symbol must be used. It is the symbol that represents the functions name. So, the name of the mac function is :mac.

Now, consider the function, :mac. :mac takes a hash as a parameter. Inside the function, the local variable, v is assigned either the value attached to the key :n, or 1 if :n has no value. :mac then returns the sum of its local variable v, and the number 6.

Finally, the function call of :fritter, with the parameters of the :mac function, and the numeral 6 ( note that this 6 id different from the 6 within the body of :mac. So, :fritter is called, and it returns the return value of :mac called itself with a parameter of 6!

Somewhat convoluted? Admittedly, this example is. But its the idea that is important. You can change the functions to solve whatever problem you're working on. Here I wanted to show just the mechanics of passing a function a function.

Passing Lambdas to a Function in Ruby


@even = ->( n ) { n % 2 == 0 }

def fun( e, n )
  e.call( n )
end

def negate( e, n )
  !e.call( n )
end

The lambda here, @even, simply takes an input parameter of n, and tests to see if it is even.
The function, :fun, simply calls the @even lambda with the numeral parameter, n that is passed in.

The function, :negate, literally does the opposite of :fun. It does this in a very simple way: it literally
negates the @even function called with the numerical parameter, n.


fun( @even, 2 )
#=> true
fun( @even, 1 )
#=> false
negate( @even, 2 )
#=> false
negate( @even, 1 )
#=> true

Both of the functions are called, each with an even value, and an odd value. They return the expected boolean results.

Comments

Popular posts from this blog

Codeigniter vs. Kohana Database access speeds

I was doing some basic profiling for a project in which I needed the fastest raw speed I could get with database queries. I'm a fan of Codeigniter for projects that are suitable for it, but had heard from some that Kohana was faster, so I decided to do a very basic comparison of the two. I was using MAMP for OSX, and created a very small db, with a table that had 3 fields: (id), (first), and (last). The data sample was also very small, only a few records. The basic query I tested was a "SELECT * FROM [table]". There is of course nothing remotely scientific about this. It was just a quick ad dirty, very limited comparison. Take it as such. Versions used: CI2.1.3, Kohana 3.3.0. Codeigniter I really like Codeigniter (CI). But, one thing that is very evident from their own profiling functions, is that CI is a bit of a memory hog! Essentially, the same Controller function running in CI takes approximately 10X more memory than in Kohana! This in itself is not ...

Java application opening then immediately closing on OSX

I have had several occasion's where Java apps would open, and then immediately close.  Often, I don't have the time to dig into the reason, as they aren't crucial.  So, I just move on. Recently, I was maddened by this happening to an application ( see other blog post on Kindle Previewer ) I really needed to use, so I had to get into the trench.  After cracking open the app, and rooting through the various files, I did some spot-checks of the java version used to build the jars ( 2 bytes at offsets 6 & 7 ), as well as had a look at the info.plist, which had the JVMVersion key set at 1.5+. Since Oracle took over Java, Apple has essentially abandoned it to them, and hasn't done an update I *think* since version 6. All of Apple's Tooling for Java stops with JVMVersion key's of 6* and 6+.  The short answer to all this is, if something was built using Apple's AppBundler tools, and you have updated Java on your Mac to 7 or above, you're probably SOL to g...

Add pre-compiled Elixir on OS X

So, I've been a big Erlang fan for a few years now, and then found out about Elixir :  what I would describe as kind of a Ruby -ish creamy frosting on top of Erlang . But I'll address more on both in future. Right now, I thought I'd just give a quick and dirty way to add Elixir , if you've already got Erlang installed (hint: check-out this Erlang Solutions link for a pre-compiled Erlang solution).  You can also use brew to install both , but I have found that with the simplicity of brew, you give up having the most current version of software.  In both cases. The pre-compiled zip for the most current version of  Elixir can be found here .  Unzipping reveals a folder containing everything you need.  For simplicity's sake, keeping everything pertaining to Elixir all within this folder makes the most sense.  By doing so, all that's needed is to position the folder, and then make links to all the executables in a directory already in our path.  Through t...