Search code examples
scalascala-cats

Optional parse from stream with State monad


I'm new to cats. I'm creating State instances to handle deserialisation of types from a byte stream. e.g.

  val int: State[Seq[Byte], Int] = State[Seq[Byte], Int] {
    case bs if bs.length >= 4 =>
      bs.drop(4) -> ByteBuffer.wrap(bs.take(4).toArray).getInt
    case _ => throw new EOFException()
  }

I have implemented a parser of Option[Int] in terms of the above, like so:

val unit: State[Seq[Byte], Unit] = State[Seq[Byte], Unit](_ -> Unit)

val optInt: State[Seq[Byte], Option[Int]] = int.flatMap(i => 
  if (i == 1) int.map(Some(_)) else unit.map(_ => None)
)

I feel that I've missed a trick here, as the implementation seems too verbose. Can I write this more succinctly? Can I do away with needing to define unit?


Solution

  • I wouldn't say that's too verbose, but I'd do two tricks with this:

    1. Replace conditional with pattern matching function
    2. Use State.pure instead of manually creating/transforming State values such as your unit.

    val optInt: State[Seq[Byte], Option[Int]] = int.flatMap {
      case 1 => int.map(Some(_))
      case _ => State.pure(None)
    }