How to handle a long sequential composition in Scala Parser Combinators? - scala

How can I process a sequential composition such as
(String, String) ~ (String, String) ~ (String, String) ~ (String, String) ~ (String, String) ~ (String, String) ~ (String, String) ~ (String, String) ~ (String, String) ~ (String, String) ~ (String, String) ~ (String, String) ~ (String, String) ~ (String, String) ~ (String, String)?
Normally I would handle it as
def member: Parser[(String, Any)] =
stringLiteral~":"~value ˆˆ
{ case name~":"~value => (name, value) }
How to handle a long sequential composition?
My goal is to create a Map of all (String, String) pairs.
If I try to do it similar way then it would look as
^^ {
case (str1, str2) ~ (str3, str4) ~ (str5, str6).... => {
// Add all (k,v) into a Map[String, String]
}
}

Related

Scalamock : How to specify arbitrary sequence of tuples

I am trying to create a mock for Play's WSClient like this:
def mockGet[A](url : String, method : String, headers : Seq[(String, String)], timeout : Duration)(
response: Future[AhcWSResponse]
) =
(mockWsClient
.url(_ : String)
.withMethod(_ : String)
.withHttpHeaders(_: (String, String)*)
.withRequestTimeout(_ : Duration)
.stream())
.expects(url, method, headers, timeout)
.returning(response)
The problem is the withHttpHeaders - this actually takes (String, String)* but when I specify that type as above I get a compiler error like this:
[error] found : Seq[(String, String)]
[error] required: (String, String)
[error] .withHttpHeaders(_: Seq[(String, String)])
What type do I need to specify for this method because (String, String) is not correct. The actual real definition of this method is:
override def withHttpHeaders(headers: (String, String)*): Self
UPDATE
I tried this after #Mario's suggestion:
def mockGet[A](url: String, method: String, headers: Seq[(String, String)], timeout: Duration)(
response: (String, String, Duration) => Future[ws.WSResponse]
) =
(
(
xs: Seq[(String, String)]
) =>
mockWsClient
.url(_: String)
.withMethod(_: String)
.withRequestTimeout(_: Duration)
.withHttpHeaders(xs: _*)
.stream()
)
.expects(headers)
.returning(response)
but this crashes the compiler with:
[error] value x$1
The key is to understand how the anonymous function placeholder parameter syntax works. For example, given
def f(i: Int*) = ???
then
f(_: Int)
expands to
(i: Int) => f(i)
Hence try
def mockGet(headers : Seq[(String, String)) =
((xs: Seq[(String, String)]) => mockWsClient.withHttpHeaders(xs: _*)).expects(headers)
Here is a simplified example
trait Zar {
def f(i: Int*) = i
}
class ScalamockVarargsSpec extends FlatSpec with Matchers with MockFactory {
"Varargs" should "be mockable" in {
val zar = mock[Zar]
((xs: Seq[Int]) => zar.f(xs: _*)).expects(Seq(1,2))
zar.f(1,2)
}
}
In your particular case there are multiple anonymous function placeholder parameters, so try expanding them all, for example
def mockGet(url: String, headers : Seq[(String, String)) =
((u: String, xs: Seq[(String, String)]) => mockWsClient.url(u).withHttpHeaders(xs: _*))
.expects(url, headers)

Type of "foreach" in Scala

I have example code:
def test = {
val l : Seq[(String, String)] = Seq()
val foo : (String, String) => Unit = {case (a, b)=>}
l.foreach[Unit](foo)
}
It gives me the next error:
Error:(8, 21) type mismatch;
found : (String, String) => Unit
required: ((String, String)) => Unit
l.foreach[Unit](foo)
As far as I understand foreach has a type (A=>U)=>Unit where:
A is template parameter of my collection and
U is template parameter of foreach itself
My question is why is ((String, String)) => Unit required? Where do the extra brackets come from?
If you check in the REPL, you'll see that foo is a <function2>, that is, a function that takes 2 argument:
scala> val foo : (String, String) => Unit = {case (a, b)=>}
foo: (String, String) => Unit = <function2>
.foreach however expects a function that takes a single arguement (of type A), which in your case is a Tuple2.
If you set foo to be a <function1>, then it works:
scala> val foo : ((String, String)) => Unit = {case (a, b)=>}
foo: ((String, String)) => Unit = <function1>
scala> val l : Seq[(String, String)] = Seq()
l: Seq[(String, String)] = List()
scala> l.foreach[Unit](foo)
scala>
Let's start from top.
You have
val l: Seq[(String, String)]
that is a Seq of tuples of two strings. So each of the elements of l is of type (String, String) which is a syntactic sugar for Tuple2[String, String].
Now you have
val foo: (String, String) => Unit
that is a function of two arguments each being String. Again, the type signature above is syntactic sugar for Function2[String, String, Unit].
Considering the above your code can be rewritten as follows:
def test = {
val l: Seq[Tuple2[String, String]] = Seq()
val foo: Function2[String, String, Unit] = {case (a, b)=>}
l.foreach[Unit](foo)
}
foreach expects a single argument function, i.e. a Function1[T, R], thus the type mismatch.
The type definition foo: (String, String) => Unit says that foo is a function which takes two parameters of type String. However, your sequence l: Seq[(String, String)] contains tuples of type type t = (String, String). Thus, calling l.foreach expects a function which is applicable to the tuple type t. Thus, it expects a function of type t => Unit, which is equivalent to ((String, String)) => Unit.

How does find function in Map work in Scala?

I am new to Scala. This is the code that I have written.
object Main extends App {
val mp: Map[String, String] = Map[String, String]("a"->"a", "b"->"b", "c"->"c", "d"->"d")
val s: Option[(String, String)] = mp.find((a: String, b: String) => {
if(a == "c" && b == "c") {
true
}
else {
false
}
})
println(s)
}
I am getting the following error.
error: type mismatch;
found : (String, String) => Boolean
required: ((String, String)) => Boolean
What am I doing wrong?
You need to change
mp.find((a: String, b: String) =>
to either
mp.find(((a: String, b: String)) =>
or
mp.find( case (a: String, b: String) =>
What you have coded is a function expecting two parameters, but you will only be passing in one, which is a Pair (also called Tuple2). The extra braces and the case keyword are ways of specifying that you are only passing in the one parameter, which is an instance of a Pair.
The problem is that find expects a function that takes a single argument, a Tuple2 in this case and returns a Boolean: ((String, String)) => Boolean. However, what you have there is a function that takes two args a and b, not a tuple (brackets matter): (String, String) => Boolean.
Here is one way to fix it. In this case I use pattern matching to extract arguments:
object Main extends App {
val mp: Map[String, String] = Map[String, String]("a"->"a", "b"->"b", "c"->"c", "d"->"d")
val s: Option[(String, String)] = mp.find{ case(a, b) => a == "c" && b == "c" }
println(s)
}
alternatively you could also do:
val s: Option[(String, String)] = mp.find(t => t._1 == "c" && t._2 == "c")
Either would print:
Some((c,c))

How to write a scala function which receives a map function to a generic type

Using Spark 1.3.0 with Scala, I have two functions which basically do the same on a given RDD[(Long, String, Boolean, String)], up to a specifc map function from (Long, String, Boolean, String) to a tuple of 2 elements:
def rddToMap1(rdd: RDD[(Long, String, Boolean, String)]): Map[Long, Set[(String, Boolean)]] = {
rdd
.map(t => (t._1, (t._2, t._3))) //mapping function 1
.groupBy(_._1)
.mapValues(_.toSet)
.collect
.toMap
.mapValues(_.map(_._2))
.map(identity)
}
def rddToMap2(rdd: RDD[(Long, String, Boolean, String)]): Map[(Long, String), Set[String]] = {
rdd
.map(t => ((t._1, t._2), t._4)) //mapping function 2
.groupBy(_._1)
.mapValues(_.toSet)
.collect
.toMap
.mapValues(_.map(_._2))
.map(identity)
}
I want to write a generic function genericRDDToMap which I would later use to implement rddToMap1 and rddToMap2.
This doesn't work:
def genericRDDToMap[A](rdd: RDD[(Long, String, Boolean, String)], mapFn: (Long, String, Boolean, String) => A) = {
rdd
.map(mapFn) //ERROR
.groupBy(_._1)
.mapValues(_.toSet)
.collect
.toMap
.mapValues(_.map(_._2))
.map(identity)
}
The (Eclipse) interpreter doesn't take mapFn as a valid mapping function, it says:
type mismatch; found : (Long, String, Boolean, String) => A required: ((Long, String, Boolean, String)) => ?
And even if I got over this, how would it know that my generic type A has value _1 in the groupBy to follow?
To summarize: how do I do it right?
You missed parentheses around (Long, String, Boolean, String). And if A is of type TupleX, you can use upper bound to specify it (here I used Tuple2):
def genericRDDToMap[X, Y, A <: Tuple2[X,Y]](rdd: RDD[(Long, String, Boolean, String)],
mapFn: ((Long, String, Boolean, String)) => A) (implicit ev: ClassTag[A])= {
...
}

How to define Scala closure with explicit return type

Why doesn't this work in scala:
val cloz: (Int,String => String) = (num: Int, str: String) => {
str+"-"+num
}
I see a few examples of closures being defined with only 1 arg, like this:
val thingy: (Int => Int) = (num: Int) => {
num * 2
}
But absolutely nowhere (including Scala ebooks) could I find any information explaining the syntax of "val" closures.
Thanks!
Jamie
The correct syntax is:
val cloz: (Int, String) => String = (num: Int, str: String) => {
str + "-" + num
}
By the way, in this simple case you can also simplify expression like this (especially if you already explicitly specifying the type of the function):
val cloz: (Int, String) => String = (num, str) => str + "-" + num
Update
You can also use REPL to explore Scala - it's very nice tool. You can start it just by starting scala without any arguments. Here is example session:
scala> val cloz = (num: Int, str: String) => str + "-" + num
cloz: (Int, String) => java.lang.String = <function2>
scala> val cloz: (Int, String) => String = (num: Int, str: String) => {
| str + "-" + num
| }
cloz: (Int, String) => String = <function2>
scala> val cloz: (Int, String) => String = (num, str) => str + "-" + num
cloz: (Int, String) => String = <function2>
scala> def printCloz(cloz: (Int, String) => String, num: Int, str: String) = print(cloz(num, str))
printCloz: (cloz: (Int, String) => String, num: Int, str: String)Unit
As you can see it not only allows you to interactively execute code, but also prints type information if you define something.
Based on the excellent answer from #Eazy Angel, I offer this for anyone who's confused as I was:
val cloz: (Int,String) => String = (num, str) => {
str+"-"+num
}
def f1( clozArg: ((Int,String) => String), intArg: Int, stringArg: String ): String = {
clozArg(intArg,stringArg)
}
println("f1 result="+f1(cloz, 5, "okee"))
Please note however (please correct me if I'm wrong) that b/c of Scala's type inference you are not required to specify all these types explicitly. The only time I have seen so far that you must do is when using recursion.
--
UPDATE:
This bizarre syntax works also: (see return type on 3rd line)
val cloz = (num: Int, str: String) => {
str+"-"+num
} : String
def f1( clozArg: ((Int,String) => String), intArg: Int, stringArg: String ): String = {
clozArg(intArg,stringArg)
}
println("f1 result="+f1(cloz, 5, "okee"))