Wednesday, October 23, 2013

Scala For-Expressions

So as you know from my last post I've been taking an online scala course through Coursera. I am currently in week 6 of 7 and it's been a lot of tough fun so far. It's definitely hard to wrap my mind around all of these functional concepts in 6 weeks time, but I'm learning more and more everyday.

This week we are focusing on Collections. Throughout this course we've been introduced and done a lot of things with Lists, but now we're doing more: Ranges, Sequences, Vectors, Maps, etc. Yesterday's example was especially intriguing to me in just the robustness and conciseness of the scala language.

The example was: Find all pairs of numbers (i, j) such that i + j is prime, where 1 < j < i < n, n is a natural number.

To start, we need a isPrime function. In java it might look like:
 private static boolean isPrime(int n) {  
      for (int i = 2; i < n; i++) {  
           if (n % i == 0) {  
                return false;  
           }  
      }  
      return true;  
 }  

But in scala, we were able to write it as:
 def isPrime(n: Int): Boolean =  
   (2 until n) forall (i => n % i != 0)   

Already, we can see the power of Collections in scala by being able to define a Range (2 until n) and then a forall loop over all integers in that Range.

Next, we need to loop over the range 1 < j < i < n and check to see if any i + j pairs are prime. In java, this might look like the following:
 int n = 7;  
 List<Pair> pairs = new ArrayList<Pair>();  
 for (int i = 1; i < n; i++) {  
      for (int j = 1; j < i; j++) {  
           if (isPrime(i + j)) {  
                pairs.add(new Pair(i, j));  
           }  
      }  
 }  
 System.out.println(pairs);  
Note: Pairs is a simple class that I made for this example

And in scala, we did this 2 separate ways. The first is using maps and filtering:
 val pairs = (1 until n) flatMap (i =>  
   (1 until i) map (j => (i, j))) filter (pair =>  
   isPrime(pair._1 + pair._2))  
 println(pairs)  

And the second way we used for-expressions:
 val pairs = for {  
   i <- 1 until n  
   j <- 1 until i  
   if isPrime(i + j)  
  } yield (i, j)  
 println(pairs)  

We can clearly see that the for-expression is the most concise and arguably the most readable out of the three implementations.

I just thought this for-expression example we did was pretty neat and worth writing about. I'm definitely looking forward to the rest of this week and next week to see what other cool features scala has to offer with its Collection manipulation.