Alex Rivera | Logout

Confused with the for-comprehension to flatMap/Map transformation

Asked 2013-01-30T07:49:35.360
101

I really don't seem to be understanding Map and FlatMap. What I am failing to understand is how a for-comprehension is a sequence of nested calls to map and flatMap. The following example is from Functional Programming in Scala

def bothMatch(pat:String,pat2:String,s:String):Option[Boolean] = for {
            f <- mkMatcher(pat)
            g <- mkMatcher(pat2)
 } yield f(s) && g(s)

translates to

def bothMatch(pat:String,pat2:String,s:String):Option[Boolean] = 
         mkMatcher(pat) flatMap (f => 
         mkMatcher(pat2) map (g => f(s) && g(s)))

The mkMatcher method is defined as follows:

  def mkMatcher(pat:String):Option[String => Boolean] = 
             pattern(pat) map (p => (s:String) => p.matcher(s).matches)

And the pattern method is as follows:

import java.util.regex._

def pattern(s:String):Option[Pattern] = 
  try {
        Some(Pattern.compile(s))
   }catch{
       case e: PatternSyntaxException => None
   }

It will be great if someone could shed some light on the rationale behind using map and flatMap here.

Edit
Report

1 Answer

0

First, mkMatcher returns a function whose signature is String => Boolean, that's a regular java procedure which just run Pattern.compile(string), as shown in the pattern function. Then, look at this line

pattern(pat) map (p => (s:String) => p.matcher(s).matches)

The map function is applied to the result of pattern, which is Option[Pattern], so the p in p => xxx is just the pattern you compiled. So, given a pattern p, a new function is constructed, which takes a String s, and check if s matches the pattern.

(s: String) => p.matcher(s).matches

Note, the p variable is bounded to the compiled pattern. Now, it's clear that how a function with signature String => Boolean is constructed by mkMatcher.

Next, let's checkout the bothMatch function, which is based on mkMatcher. To show how bothMathch works, we first look at this part:

mkMatcher(pat2) map (g => f(s) && g(s))

Since we got a function with signature String => Boolean from mkMatcher, which is g in this context, g(s) is equivalent to Pattern.compile(pat2).macher(s).matches, which returns if the String s matches pattern pat2. So how about f(s), it's same as g(s), the only difference is that, the first call of mkMatcher uses flatMap, instead of map, Why? Because mkMatcher(pat2) map (g => ....) returns Option[Boolean], you will get a nested result Option[Option[Boolean]] if you use map for both call, that's not what you want .

answered 2013-01-30T08:14:11.987

Your Answer