A multilingual example originally from PythonVsRuby ''I added some nitpicking comments below, but the largest nitpick is of whether a language even supports "blocks" in the first place.'' ---- The statement "lambdas cannot change variables" is meaningless. * ''Except in PythonLanguage, where it's both meaningful and true.'' * Then it's not "lambda", which has a precise definition in the lambda calculus, it would then be something else, e.g. maybe "python-pseudo-lambda". In functional languages, lambda is the semantic method that binds local symbols to values, nothing more and nothing less. That is not a matter of taste in language constructs, it's a matter of definition. * The above claim 'The statement "lambdas cannot change variables" is meaningless.' sounds like it originated in some discussion that is now missing. Lambdas inherently define bindings for the variables that they define within their scope, and they do not do/say anything about variables outside their scope; the latter is a question of sub-theory or of implementation, e.g. Lisp macro variable capture versus hygenic macros without capture. A lambda is a form for function creation. If you want to use only lambdas then you can translate from a notation that uses assignment to a notation that uses only lambdas. See LambdaTheUltimateImperative. * It's not false to say "lambda is a form for function creation", but that can be misleading. Less misleading is to say that "lambda is a form for binding formal parameters to actual parameters", which then allows a body of code to receive different semantic interpretations in different points of application. (I would not be surprised if there is disagreement on this point, but I believe alternate points of view boil down to the same thing.) In SchemeLanguage you could use assignment like this: (let ((input (open-input-file "~/test.txt")) (count 0)) (let loop ((line (read-line input))) (if (eof-object? line) (format "~a lines in test.txt" count) (begin (set! count (+ count 1)) (loop (read-line input)))))) Or you could translate into lambdas like this: (let ((input (open-input-file "~/test.txt"))) (let loop ((line (read-line input)) (count 0)) (if (eof-object? line) (format "~a lines in test.txt" count) (loop (read-line input) (+ count 1))))) Where ''let'' is just pretty syntax for a lambda: (let ((a 1) (b 2)) (+ a b)) => ((lambda (a b) (+ a b)) 1 2) Generators and iterators also are just syntax for lambdas. The question is why would local assignment be preferred over a functional style of programming? FunctionalProgramming is more modular, and modular is more agile, and more agile is better. ''Many people find imperative programs easier to understand, per-line; but that's a side point. The main point is that PythonLanguage, like many other languages, doesn't support FunctionalProgramming very well. For example, it doesn't have TailRecursion, so the above program in Python only works for files under 1000 lines. But even if that weren't the case, it isn't really valid to say, "The limitation in this language construct X doesn't really exist because, by performing a global transformation on your program, you can get an equivalent program in which that limitation doesn't matter."'' Here's a PythonLanguage version of the LispLanguage above. It can't be written in terms of Python lambda because Python lambda doesn't allow conditionals. infile = file('test.txt') def loop(line, count): if not line: print count, "lines in test.txt" else: loop(infile.readline(), count + 1) loop(line=infile.readline(), count=0) Though why one would use this instead of (say): print len(list(file('c:/text.txt'))), "lines in test.txt" or: print "%d lines in test.txt" % len(open("test.txt").readlines()) is another matter (Well ok, OneLinersAreEvil ;-) ''It can't be written in terms of Python lambda because Python lambda doesn't allow conditionals.'' Is that a challenge? import sys infile = file('test.txt') loop = lambda line, count: ( (lambda: sys.stdout.write(str(count) + " lines in text.txt\n")), (lambda: loop(infile.readline(), count+1)) )[bool(line)]() loop(infile.readline(), 0) or: import sys infile = file('test.txt') loop = lambda line, count: ( (line or sys.stdout.write(str(count) + " lines in text.txt\n")) and loop(infile.readline(), count + 1) ) loop(infile.readline(), 0) ''or you could go the LambdaCalculus-esque way:'' import sys def lambdaConditional(b): if b: lambda a b: a() else: lambda a b: b() def loop(line,count): lambdaConditional(not line)(lambda (): print count, "lines in test.txt", lambda (): loop(infile.readLine(),count+1)) ''although I'm fairly certain that's not "good PythonLanguage" and GuidoVanRossum would crucify me for it. --HarrisonHoughton'' ---- ''Generators and iterators can be implemented in RubyLanguage using BlocksInRuby; there is no need for additional language mechanisms. E.g.:'' def counter_from( n ) proc do result = n n = n + 1 result end end counter = counter_from( 3 ) print counter.call() >>> 3 print counter.call() >>> 4 print counter.call() >>> 5 ''On the other hand, the PythonLanguage designers chose to add new language mechanisms for generators and iterators, rather than adding a generic mechanism for capturing closures, and then building generators and iterators on top of that.'' ...and Ruby designer(s?) (YukihiroMatsumoto) chose to add blocks with yield, rather that adding a generic mechanism for calling HigherOrderFunction''''''s... The Python version is: def counter_from(n): while 1: yield n n += 1 counter = counter_from(3).next print counter() print counter() print counter() ''You can do HOF in RubyLanguage as in PythonLanguage, you just need to create Method objects from messages explicitly. Blocks fits a slightly different niche than function composition: they allow intuitive usage of '''some''' higher order functions, say: open('foo.txt').each do |line| puts line if line.length == 10 end happily using lambda without need to understand it '' [I find it interesting that the "cool trick" of using a block to implement a counter is considered a plus for Ruby. In Smalltalk circles, implementations of blocks that reuse their variables are considered defective. I leave it as an exercise to the reader to determine why such implementations of blocks are defective, though you can rest assured that they are. I consider it proof that RubyIsSmalltalkMinusMinus when Ruby programmers are proud of its defects. Very much like C++ and Java.] ''If my understanding of SmalltalkBlocksAndClosures is correct, Smalltalk implementations don't necessarily allocate space for the block variables, so reusing variables in Smalltalk blocks could well result in UndefinedBehavior?'' ---- C# supports anonymous methods (blocks) and Icon-style iterators. The Ruby counter_from routine could be rewritten using anonymous methods: Func counter_from( int n ) { int result = n; return delegate () { return result++; }; } Func counter = counter_from( 3 ) Console.Write''''''Line(counter()) >>> 3 Console.Write''''''Line(counter()) >>> 4 Console.Write''''''Line(counter()) >>> 5 or using iterators: IEnumerable counter_from( int n ) { while (true) yield return n++; } foreach (int n in counter_from(3)) { if (n > 5) break; Console.Write''''''Line(n) } >>> 3 >>> 4 >>> 5 ---- PhpLanguage function counter_from($n) { $i = $n; return function()use(&$i) { return $i++; }; } $counter = counter_from(3); echo $counter,"\n"; echo $counter,"\n"; echo $counter,"\n"; Variables in the outer scope that are to be visible in the inner scope have to be explicitly imported; if the inner scope's modifications of those variables (if any) are to be visible in the enclosing scope (as here where the updated value of $i needs to persist) then the import has to be by reference. ---- '''ScalaLanguage''' In ScalaLanguage a block is just an expression made up of more than one expression and is normally only evaluated once: val v = { println("evaluating v"); 3 } The above will print "evaluating v" immediately and v will be 3. A function literal is closer to what this page is talking about: val v = { () => Int println("applying v"); 3 } The above will print nothing and v will be a function. Evaluating "v()" will print "applying v" each time and evaluate to 3. To get blocks that get evaluated each time they are used but don't look like functions, ScalaLanguage has call-by-name: def f(b: => Int) { println(b) println(b) } f { println("evaluating block") 3 } The above will print "evaluating block" and then "3" twice. Using call-by-name and implicit conversions, we can add a ruby-like "times" method to Int: class RubyLikeInt(self: Int) { def times(b: => Unit) = (1 to self) foreach (_ => b) } implicit def rubyLikeInt(i: Int) = new RubyLikeInt(i) 3 times { println("Hello World!") } Of course, since a block in ScalaLanguage is just a way to group multiple expressions, the last expression above could be written without the braces: 3 times println("Hello World!") ---- '''CeePlusPlus''' C++11 lambdas may capture stack variables by copy or by reference. Sadly, captured references will cause UndefinedBehavior if they escape their parent stack frame. The counter example is implemented as follows: std::unique_ptr> make_counter(int n = 0) { return [=]() mutable { return n++; } } --- '''GoLanguage''' In Go, functions close over the outer scope, and the runtime will make sure to keep closed-over variables alive with the closure: func Counter(n int) func() int { x := n return func() int { x++ return x } } ---- See BlocksInJava, BlocksInJavaScript, BlocksInObjectiveCee, BlocksInPython, BlocksInRuby, BlocksInCsharp, CoroutinesInDotNet, RubyBlocksVsSmalltalkBlocks ---- CategoryFunctionalProgramming | CategoryClosure | CategoryComparisons | CategoryInManyProgrammingLanguages