Mahsa
Mahsa

Reputation: 1550

How to parse two different types in one parser in Scala?

I have written the following part of code to parse RDD type and Float in an expression. To parse an arithmetic expression consisting float and RDD like: "firstRDD + 2" :

def term2: Parser[List[Either[Float, RDD[(Int,Array[Float])]]]] = rep(factor2)
def factor2: Parser[Either[Float, RDD[(Int,Array[Float])]]] = pathxml | num  
def pathxml: Parser[RDD[(Int,Array[Float])]] = pathIdent ^^ {s => pathToRDD(s) } //pathToRDD is a function that gets the path in string and create an RDD from the file inside that path and pathIdent parse to see whether the input string is a path or not
def num: Parser[Float] = floatingPointNumber ^^ (_.toFloat)

Now I am getting this error:

  [error] type mismatch;
  [error]  found   : ParseExp.this.Parser[Float]
  [error]  required: ParseExp.this.Parser[Either[Float,org.apache.spark.rdd.RDD[(Int, Array[Float])]]]
  [error]   def factor2: Parser[Either[Float, RDD[(Int,Array[Float])]]] = pathxml | num 
  [error]                                                                           ^

I don't know how to do that except using "Either" and don't know how to solve this type mismatch! Note that if I use "Any" it is not able to parse the RDD.

Upvotes: 0

Views: 159

Answers (1)

Reactormonk
Reactormonk

Reputation: 21700

It wants an Either instead of a Float, so you give it an Either. But we cannot simply create the value from the output, because the Parser works with functions, not values.

def num: Parser[Either[Float, RDD[(Int,Array[Float])]]] = floatingPointNumber ^^ (n => Left(n).toFloat)

and hope it works. If it doesn't, go the long route:

def num: Parser[Either[Float, RDD[(Int,Array[Float])]]] = floatingPointNumber ^^ (n =>
  val res: Either[Float, RDD[(Int,Array[Float])]] = n.toFloat
  res
)

Or the scalaz route (you'll have to rewrite the code to use \/ instead of Either:

import scalaz._
import Scalaz._

def term2: Parser[List[\/[Float, RDD[(Int,Array[Float])]]]] = rep(factor2)
def factor2: Parser[\/[Float, RDD[(Int,Array[Float])]]] = pathxml | num
def pathxml: Parser[RDD[(Int,Array[Float])]] = pathIdent ^^ {s => pathToRDD(s) } //pathToRDD is a function that gets the path in string and create an RDD from the file inside that path and pathIdent parse to see whether the input string is a path or not
def num: Parser[\/[Float, RDD[(Int,Array[Float])]]] = floatingPointNumber ^^ (n => n.left[RDD[(Int,Array[Float])]].toFloat)

left and right from scalaz do pretty much what you would expect - they create a left or a right value. The type argument you pass to left or right is used to construct the full type, because the value only provides the left or right type, but the full either type needs the type of the other side (right/left) as well, so the other type needs to be passed as well.

On another hand, I think you'll get a similar error message later with pathxml. Fix it in a similar manner, except with Right instead of Left.

Upvotes: 1

Related Questions