Another question was launched (which was subsequently edited), I wanted to try how easy it would be to forward calls to Scala 2.10 Try (see this presentation ), using for understanding.
The idea is to have a list of tokens and match them to a sequence of patterns, and then return the first error or pattern with a successful match. I came to the next rather inconvenient version, and I wonder if it can be made easier and more pleasant:
import util.Try trait Token case class Ident (s: String) extends Token case class Keyword(s: String) extends Token case class Punct (s: String) extends Token case object NoToken extends Token case class FunctionDef(id: Ident) case class Expect[A](expectation: String)(pattern: PartialFunction[Token, A]) { def unapply(tup: (Try[_], Token)) = Some(tup._1.map { _ => pattern.lift(tup._2).getOrElse(throw new Exception(expectation)) }) }
Now let's build expectations for Keyword("void") :: Ident(id) :: Punct("(") :: Punct(")") :: tail
val hasVoid = Expect("function def starts with void") { case Keyword("void") => } val hasIdent = Expect("expected name of the function") { case id: Ident => id } val hasOpen = Expect("expected opening parenthesis" ) { case Punct("(") => } val hasClosed = Expect("expected closing parenthesis" ) { case Punct(")") => }
Build a complete test case:
def test(tokens: List[Token]) = { val iter = tokens.iterator def next(p: Try[_]) = Some(p -> (if (iter.hasNext) iter.next else NoToken)) def first() = next(Try()) val sq = for { hasVoid (vd) <- first() hasIdent (id) <- next(vd) hasOpen (op) <- next(id) hasClosed(cl) <- next(op) } yield cl.flatMap(_ => id).map(FunctionDef(_)) sq.head }
The test method is tested below:
// the following fail with successive errors test(Nil) test(Keyword("hallo") :: Nil) test(Keyword("void" ) :: Nil) test(Keyword("void" ) :: Ident("name") :: Nil) test(Keyword("void" ) :: Ident("name") :: Punct("(") :: Nil) // this completes test(Keyword("void" ) :: Ident("name") :: Punct("(") :: Punct(")") :: Nil)
Now especially the extra flatMap and map in yield seem terrible, as well as the need to call head result of the result for understanding.
Any ideas? Is Try very suitable for understanding? Is it possible to "t211" or Try to "commit" to allow this type of streaming (for example, allow Try as a direct result type unapply )?