Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

scala foreach and map initializers

Just seen an interesting possibility to initialize code blocks in Scala for high order functions such as foreach or map:

(1 to 3) map {
  val t = 5
  i => i * 5
}


(1 to 3) foreach {  
  val line = Console.readLine  
  i => println(line)  
}  

Is this some documented feature or should I avoid such constructs? I could imagine, the "initialization" block comes into the constructor and the closure itself becomes an apply() method?

Thanks Pat for the original Question (http://extrabright.com/blog/2010/07/10/scala-question-regarding-readline)

like image 281
Slava Schmidt Avatar asked Jul 10 '10 20:07

Slava Schmidt


2 Answers

While the features used are not uncommon, I'll admit is is a fairly odd combination of features. The basic trick is that any block in Scala is an expression, with type the same as the last expression in the block. If that last expression is a function, this means that the block has functional type, and thus can be used as an argument to "map" or "foreach" . What happens in these cases is that when "map" or "foreach" is called, the block is evaluated. The block evaluates to a function ( i=> i*5 in the first case ), and that function is then mapped over the range.

One possible use of this construct is for the block to define mutable variables, and the resulting function mutate the variables each time it is called. The variables will be initialized once, closed over by the function, and their values updated every time the function is called.

For example, here's a somewhat surprising way of calculating the first 6 factorial numbers

(1 to 6) map {
      var total = 1
      i => {total *= i;total}
    } 

(BTW, sorry for using factorial as an example. It was either that or fibonacci. Functional Progamming Guild rules. You gotta problem with that, take it up with the boys down at the hall.)

A less imperative reason to have a block return a function is to define helper functions earlier in the block. For instance, if your second example were instead

(1 to 3) foreach {  
  def line = Console.readLine  
  i => println(line)  
}

The result would be that three lines were read and echoed once each, while your example had the line read once and echoed three times.

like image 200
Dave Griffith Avatar answered Nov 13 '22 15:11

Dave Griffith


First, the comment of the original blog "Scala Question Regarding readLine" post mention

The “line” is a value and cannot be executed, it is assigned only once from the result of the “Console.readLine” method execution.
It is used less than three times in your closure.
But if you define it as a method, it will be executed three times:

(1 to 3) foreach {
  def line = Console.readLine
  i => println(line)
}

The blog Scala for Java Refugees Part 6: Getting Over Java has an interesting section on Higher Order function, including:

Scala provides still more flexibility in the syntax for these higher-order function things.
In the iterate invocation, we’re creating an entire anonymous method just to make another call to the println(String) method.
Considering println(String) is itself a method which takes a String and returns Unit, one would think we could compress this down a bit. As it turns out, we can:

iterate(a, println)

By omitting the parentheses and just specifying the method name, we’re telling the Scala compiler that we want to use println as a functional value, passing it to the iterate method.
Thus instead of creating a new method just to handle a single set of calls, we pass in an old method which already does what we want.
This is a pattern commonly seen in C and C++. In fact, the syntax for passing a function as a functional value is precisely the same. Seems that some things never change…

like image 37
VonC Avatar answered Nov 13 '22 14:11

VonC