1

I'm studying Michael Pilquist's excellent state monad lecture here. I get stuck at 54 min with two questions.

  1. If ofs is an Option[FollowerStats], what is the ? operator? I can't find a ternary operator on Option in Scala 2.10.2

  2. How does the last generator put an updated cache (with hit or miss incremented) back into the State result of the checkCache method? The returned State seems to be be discarded and the for comprehension seems to only yielding the Option[FollowerStats]

.

def checkCache(u: String): State[Cache, Option[FollowerState]] = for {
    c <- State.get[Cache]
    ofs <- State.state {
        c.get(u).collect {
            case Timestamped(fs, ts) if !state(ts) => fs
        }
    }
    _ <- State.put(ofs ? c.recordHit | c.recordMiss)
} yield ofs

To try and understand I attempted to re-write the for comprehension, but it's not helped.

State.get[Cache].flatMap{ c => 
    State.state{c.get(u).collect(...)}.flatMap{ ofs =>
        State.put(ofs ? c.recordHit | c.recordMiss).map{ _ =>
            ofs
        }
    }
}

Update: I think I've grasped the key to point 2 thanks to the answers. I didn't realise that that the yield is essentially saying: take the last state s => (s,()) from the put and replace the Unit value type with ofs, to get s =>(s,ofs). I guess the key is realising that the yield isn't literally returning ofs, but it's translated as State.map.

Update Understand the option bit now. I guess the presentation still uses the implicits from Scalaz although it's deriving the state monad.

Pengin
  • 4,692
  • 6
  • 36
  • 62
  • 1
    The `Option ? ... | ...` bit comes from an implicit conversion (specifically an implicit class `OptionOps`). You have probably already dealt with implicit conversions such as being able to call `toInt` on a String due to an implicit conversion to `StringOps` - this is much the same. – Shadowlands Oct 08 '13 at 12:25
  • At 1:06:12 he actually mentions the option thing. Should have continued watching, but OCD prevented it. – Pengin Oct 08 '13 at 13:00
  • Well hopefully the next OCD sufferer watching that vid will find this question, read all the comments, and know to jump straight back to watch the rest of the vid! :) – Shadowlands Oct 08 '13 at 13:06

2 Answers2

2

First for the ternary operator.

ofs ? c.recordHit | c.recordMiss

Is to equivalent to:

if (ofs.isDefined) c.recordHit else c.recordMiss

Or:

ofs.fold(c.recordMiss)(_ => c.recordHit)

It's provided by Scalaz and implemented as an implicit class (OptionOps) that provides a ? method for Option that returns a Conditional class that has a | method. This is a case where I'm not sure the extra concision is worth the confusion, but people use it, so it's worth knowing about.

For the state update, consider the following simplified example:

val inc: State[Int, Unit] = for { i <- get[Int]; _ <- put(i + 1) } yield ()

It might look at first like we're "discarding" the state and only yielding unit, but the value of inc is actually the entire state-manipulating computation (in this case one that doesn't return any relevant or interesting value), including the update.

Travis Brown
  • 138,631
  • 12
  • 375
  • 680
1
  1. The ?| operator comes from the boolean syntax of scalaz. Have a look here at BooleanOps. It's actually 2 functions, first ? and then | on the Conditional.

  2. The updated cache is actually the result of running the State action. If you look earlier in the video, State should have been defined as something that, given a state action and an initial state s, running the state action with s results in a (a, s2) which is a pair of: (a) the value computed (represented as a in the tuple) from the passed in state and (b) the new state after the action has been executed (represented as s2).

Just note that the new Cache is not actually computed until the initial Cache is run though the monadic action.

gpampara
  • 11,989
  • 3
  • 27
  • 26