Wednesday, April 30, 2008

Why return lambda from a function?

There was an excellent question at the meetup after my presentation on why return lambda instead of the actual result from a function. I did some digging on comp.lang.ruby group. Here is highlights of the notes from that group:

> I have seen many tutorials on the Internet explaining where lambdas
> CAN be used, such as clever multiplication functions, but when are
> they actually NEEDED?

> Sure, I can take a lambda and "pass it around" so to speak, but I can
> call a function from anywhere too, right?

Sure, you can call methods from almost anywhere. But you can't pass them
around (unless you turn them into proc objects, in which case you are back to
using lambdas.) And passing them around is necessary if you didn't write (and
don't want to have to monkeypatch) all the library, etc., code from which you
may want to perform a particular task. If those libraries are written to let you
pass in proc objects, you are in good shape.

> Can somebody give me an extremely useful, NOT complicated, example of
> when lambdas are the absolute perfect solution to a problem?

Callbacks.

--------------


Every time you use a block in ruby you're using a lambda implicitly.

Implicitly, but not really. I wonder, was the original question more
like "what are blocks for?" or "yes, I know what blocks are for, but why
are there also these Proc objects, which are instantiated with the
lambda construct?"

If the latter, then one answer is: when you need the program state that
is encapsulated in a block to persist outside of the method in which it
is used. For example, this happens in event-based frameworks: a setup
method in a client class registers lambdas as event handlers; the
framework doesn't need to know the classes or methods of the client
class, hence loose coupling. As a bonus, these handlers can refer to
shared program state (local variables) in the setup method.


cache :index, :ttl => 42, :key => lambda{ request['important'] }

this is a class level method which says

"cache the index method, invalidating every 42 seconds, by using the
current request's 'important' value from the query"

note that in this cast the lambda will be instance_eval'd - so when we
say 'request' here it will ultimately mean the current request

another example:

def each &block

@list.each &block

end

here we need to have captured the calling block's scope in other to
relay it along to our internal @list object's each method. it's NOT
the case that we want the scope if the function for this lambda, what
we want is logic bound to the scope of the caller

lambda are perfect anytime you want a context sensitive result and
don't want to code everything in one massive global scope.

My problem with lambda's is that I have a hard time to find a
real use case for them. I am not sure of some use case with
lambda {} that brings a definite advantage over i.e. just
using some special object or simple method.

Technically, you can replace every lambda with
an class and an instance thereof. The difference is that
the lambda is syntactically and semantically more lightweight.

To add another example, Rake tasks store away lambdas.

my_lib_version = "1.0.2"

task :tgz do
sh "tar -czf my_lib-#{my_lib_version}.tgz lib"
end

Assuming a Ruby-like language without lambdas,
we'd get this "pure OO" Rakefile:

class TgzTask
def initialize(version)
@version = version
end
def execute
sh "tar -czf my_li...@version.tgz lib"
end
end

my_lib_version = "1.0.2"

task :tgz, TgzTask.new(my_lib_version)

All context we need in our method (local variables,
eventually the current "self") has to be explicetely
passed to the constructor, which has to initialize
our object etc. Rake would loose all its appeal.

a lambda is a special object - on that knows about every variable in
scope. have fun maintaining code that populates that object by hand ;-)

the entire point of lambdas is that the language already *has* a
scope. so, sure, you can cherry pick the required variables and
populate an object, but you can also make loops with GOTO - lambda is
merely an abstraction.

the 'definite' bit comes in because you don't HAVE to do ANYTHING.
you simply write this code

sum = 0

list.each do |i|

sum += i

end

and you don't have to write anything special, the environment is
captured, the code is evaulated in the captured context, but you don't
have to build a special summing function that take i and a sum var.

so it 'definitely' is an advantage - that is unless you don't happen
to think less code is advantageous over more...

Short answer: they are more more concise and convenient.

Ever use C++ STL? In this library a "functor" is a very important concept
(for various comparators, visiting objects, etc). You make a functor by
defining a class with a primary method for functor's functionality
("operator()"). It might also have some state (possibly maintained through
other methods) or references to things external to the functor.

In ruby, this type of thing is done with blocks and lambdas. But, it is a
lot more concise and convenient. Because blocks/lambdas have access to
variables in the scope where they are defined (which can also be used to
create state), there shouldn't be a need to create dedicated "functor"
classes.

One main use is precisely when you don't need to pass anything around - you
need a one-off function, and probably the function isn't particularly
complicated. Typical examples are when supplying a code block to a sort,
group, map or filter function.

Are they needed? No. But then again, neither are subroutines or modules or
for loops...

the lambda expression came from the lisp community, it's kind of
abstraction of procedures.
in oo languages it's usually difficult to extend methods than extend
data structures.
ruby or other modern programming languages did a great job to mix them together.
well , back to the topic, imo to fully understand the power of
lambda(or abstraction), one has to look into the lisp/scheme world :)

Lambda comes from lambda calculus. The fact that LISP uses them is just a
happy coincidence.

But let's compare LISP and Ruby for a moment.

In LISP, any time you want to pass an unnamed ad-hoc function to another
function, you define it like (lambda (var1 var2) (code)), so you wind up
using the lambda macro a lot. You might have
(mapcar #'(lambda (x) (* x x)) '(1 2 3 4))
which returns
(1 4 9 16)

In Ruby, you do this kind of thing a lot too. Only we have syntactic
sugar that makes things a little nicer in many cases. The equivalent code
to the LISP example is
[1 2 3 4].map{|x| x*x}
so you just used a lambda, but didn't have to type the keyword.

There's one thing to know though. Kernel#proc and Kernel#lambda have
slightly different semantics when it comes to the return, next, and break
keywords. Kernel#lambda does things one way, and Kernel#proc or a bare
block do things the other way. So really, Ruby uses lambdas a lot (maybe
even more than LISP) but we just don't use the term very much, mostly
because we've shortened the syntax.

I like to use them when I have to efficiently choose an algorithm based
on some value:

algos = {
"print" => lambda {|x| puts x},
"ignore" => lambda {|x| },
"log" => lambda {|x| File.open("log","w") {|io| io.puts x}},

}

Now you can efficiently call a function based on some input

...each do |x,y|
algos[x][y]
end

Yes, I know the example is artificial and yes, you can do it with an
object and #send as well. But if keys are not Strings or have different
types then this approach is simpler.

Here is the link to the actual thread : http://groups.google.com/group/comp.lang.ruby/browse_frm/thread/643980216d5c3356/2d0af8f6eabf9fb3?lnk=gst&q=proc#2d0af8f6eabf9fb3

No comments:

Post a Comment