3

Given this simple computation i can not clearly see the difference between using applicative style over monadic style. Are there some better examples out there ( in scala ) when to use the one over the other.

    println( (3.some |@| none[Int] |@| 4.some )( (a:Int,b:Int,c:Int) => {  a + b + c } )  ) // prints None

    println( for( 
     a <- Some(3);
     b <- none[Int];
     c <- Some(4)
   ) yield( a + b + c ) ) // prints None

Both computations ending up in a None so the end result is the same. The only difference i can see ist that there is no temporaray access to those vars in the for comprehension when using the applicative syntax.

Furthermore having one None value stops the whole computation. I thought applicative means "not dependent on the result of the computation before"

2
  • Maybe you should read the paper that introduced Applicative. For me, reading the paper made me understand the difference between Monad and Applicative.
    – ziggystar
    Commented Oct 14, 2015 at 14:38
  • This is hard to read ^^
    – Jay
    Commented Oct 14, 2015 at 14:43

2 Answers 2

5

The applicative builder syntax will evaluate each term and can not use the result of a prior computation. However, even if the first result is None, all the other expressions will still be evaluated.

Whereas, with the for comprehension, it will 'fail fast' (it will not evaluate any further expressions after a None, in your case), plus you can access the results of previous computations.

Don't think of these things as simply different styles, they are calling different functions with different behaviours: i.e. flatMap vs apply

7
  • But in the end the function { a + b + c } will not be called and so it looks like the same behaviour.
    – Jay
    Commented Oct 14, 2015 at 13:49
  • 1
    But each term 3.some, none[Int] and 4.some will be evaluated. Wrap them in something like {println("one"); 3}.some if you need convincing.
    – melps
    Commented Oct 14, 2015 at 13:50
  • You're right. So i think Option is a bad test case for this.
    – Jay
    Commented Oct 14, 2015 at 13:54
  • Couldn't you implement a fail-fast version of apply?
    – ziggystar
    Commented Oct 14, 2015 at 14:17
  • 1
    About your last point: many people argue that for monadic types any implementation of ap must be consistent with the one derived from flatMap. I don't find this argument entirely convincing, but that's the approach taken by Scalaz and other libraries. Commented Oct 14, 2015 at 18:10
1

Monads represent sequential computations where each next computation depends on previous ones (if previous computation is empty you can't proceed, so you "fail fast"), more generic example of monadic computation:

println( for( 
     a <- Some(1);
     b <- Some(a);
     c <- Some(a + b)
   ) yield( a + b + c ) ) //=> 4

Applicative is just fmap on steroids where not only an argument, but a mapping function itself can be empty. In your case it can be rewritten as:

4.some <*>
  { none[Int] <*>
    { 3.some <*> 
      { (_: Int) + (_: Int) + (_: Int) }.curried.some } }

On some step your function becomes Option[Int => Int] = None, but it doesn't stop from applying it to 4.some, only the result is None as expected. You still need to know the value of 4.some.

1
  • This is equal to Some(4).flatMap { a => None.flatMap { b => Some(3).map { c => a + b + c } } } ? Doesn't seem so ciz None.flatMap does not evaluate the mapping function.
    – Jay
    Commented Oct 14, 2015 at 22:02

Not the answer you're looking for? Browse other questions tagged or ask your own question.