The Power of the Lambda

In one of the (non-Ruby) applications I maintain, there is a function that is responsible for handling unit conversions. It looks something like this:

double UnitConvert(double value, string from_unit, string to_unit)

So that I can do this:

double value = UnitConvert(5.0, "feet", "inches")

The underlying part of this code has to figure out exactly how to convert between the two units. In a nutshell, there's a big hash of known unit conversions that gets loaded when the program starts up, and it can interpolate, trace paths, and figure out how to fill in any gaps that may exist. In all actuality, it's a pretty smart piece of code.

It works due to the assumption that in order to convert between units, you just multiply by some scaling factor:

double factor = CalculateScalingFactor("feet", "inches")
# factor = 12.0

But what about units that don't work this way? One obvious one that comes to mind is Farenheit to Celsius, which isn't a direct scaling but also has an offset. You could do something like this:

pair = CalculateScalingFactor("celsius", "fahrenheit")

That takes care of this rogue case, but it doesn't handle more complicated cases where there could be 2nd or 3rd order terms, or other tricky things like sines, logarithms, and exponentials.

This is where the power of the lambda really shines. Instead of returning some representation of the scaling factors required to do the conversion, why not return an anonymous function that handles the conversion for you.

Consider this piece of Ruby code:

# Conversion from Celsius to Farenheit
l = lambda { |x| x * 1.8 + 32 }

irb> l.call(0)
=> 32.0
irb> l.call(100)
=> 212.0

So now, instead of trying to return an array or more complex representation of conversion coefficients, we can simply return a lambda function that performs the conversion for us.


def convert(from,to)
  if(from == :feet and to == :inches)
    return lambda { |x| x * 12.0 }
  elsif(from == :celsius and to == :farenheit)
    return lambda { |x| x * 1.8 + 32 }
  elsif(from == :moles and to == :millinewtons_per_square_widget)
    return lambda { |x| x * Math.sin(x) * Math.exp(-x) + 33.2 }
  else
    raise "Unknown Conversion"
end

By calling this method, we get back a closed off lambda function in which we don't have to worry about the details.

All that's left is to call the function with the appropriate argument, and our converted value will be returned.


l = convert(:from_unit, :to_unit)
converted_value = l.call(some_value)

Very nice!