I am attempting to make a lexer in Scala.
I am attempting to do something like this
def lex(s: String): Expr = s match {
case num(a) => Number(a.toDouble)
case mul(a, b) => Mul(Number(a.toDouble), Number(b.toDouble))
case div(a, b) => Div(Number(a.toDouble), Number(b.toDouble))
case add(a, b) => Add(Number(a.toDouble), Number(b.toDouble))
case sub(a, b) => Sub(Number(a.toDouble), Number(b.toDouble))
case _ => Number(0)
}
where num, mul, div, add, sub are defined as so:
val num: Regex = "[0-9]+".r
val add: Regex = "[0-9]+\\s*\\+\\s*[0-9]+".r
val sub: Regex = "[0-9]+\\s*\\-\\s*[0-9]+".r
val div: Regex = "[0-9]+\\s*\\/\\s*[0-9]+".r
val mul: Regex = "[0-9]+\\s*\\*\\s*[0-9]+".r
When attempting to lex any expression (lex("1 + 2")) the result is always Number(0.0) instead of the expected Add(Number(1), Number(2))
Im not sure where it's going wrong...
You need to specify which groups you want to extract.
val num = "([0-9]+)".r
val add = "([0-9]+)\\s*\\+\\s*([0-9]+)".r
val sub = "([0-9]+)\\s*\\-\\s*([0-9]+)".r
val div = "([0-9]+)\\s*\\/\\s*([0-9]+)".r
val mul = "([0-9]+)\\s*\\*\\s*([0-9]+)".r
You need one pair of parentheses per variable you extract.
Related
I would like to add an element depending on the result of a different condition.
As it is now, I did it this way :
val add1 = if(condition1) Seq(ENUM_ELEMENT_1) else Seq()
val add2 = if(condition2) Seq(ENUM_ELEMENT_2) else Seq()
return Seq(add1, add2).flatten
If I was in Java I would just create an empty ArrayList() at the beginning and add to this list as the code encounter the ifs.
But in Scala, I would have to use a mutable object of Seq and I don't know if it's appropriate here.
Declare list of tuples with conditions on left and enums on right:
val conditions: Seq[(Boolean, Enum)] = List(
condition1 -> ENUM_ELEMENT1,
condition2 -> ENUM_ELEMENT2
)
Then you can just reduce it with collect:
val result: Seq[String] = conditions.collect{
case (true, v) => v
}
or flatMap:
val result: Seq[Enum] = conditions.flatMap{
case (true, v) => Some(v)
case _ => None
}
There is several ways to do this. Here's what come out of the blue to me:
(if(condition1) Seq(ENUM_ELEMENT_1) else Seq()) ++ (if(condition2) Seq(ENUM_ELEMENT_2) else Seq())
They are way of factorizing both of this procedure by a function or a fold but it may be overthinking at this state.
Without proper context I am unable to provide a more concrete solution, but I think this pseudo-code represents your problem.
If you have any questions, do not doubt to ask for clarification.
object ListFactory {
type Input = ???
type Output = ???
private val allElements: List[Output] =
List(ENUM_ELEMENT_1, ENUM_ELEMENT_2, ???)
private val conditions: List[Input => Boolean] =
List(???)
def apply(input: Input): List[Output] =
(allElements zip conditions).collect {
case (element, condition) if (condition(input)) => element
}
}
ListFactory(???) // res1: List[Output] = ???
This question already has answers here:
What is the formal difference in Scala between braces and parentheses, and when should they be used?
(9 answers)
Closed 6 years ago.
From this link showing some Scala examples: http://spark.apache.org/docs/latest/mllib-collaborative-filtering.html
what is the difference between map{} and map()?
val ratings = data.map(_.split(',') match { case Array(user, item, rate) =>
Rating(user.toInt, item.toInt, rate.toDouble)
})
val usersProducts = ratings.map { case Rating(user, product, rate) =>
(user, product)
}
map is a method which accepts a function as an argument. So map customarily is called just like methods get called: map(aFunction). However, Scala provides a lot of flexibility / shorthands in its syntax:
val list = List((1,2),(3,4))
//An ordinary method call. The braces just evaluate to an anonymous function
val a = list.map({ case (a, b) => a + b }) // List(3,7)
// Now lets define a non anonymous function of the same type as above:
def func(x: (Int,Int)) = x match {case (a,b) => a + b}
// Scala allows this readable "infix notation" for single parameter methods
val a = list map func // List(3,7)
//Now to the main point you asked, this syntax uses the same readable form as above
//but uses an anonymous function.
val a = list map {case (a,b) => a + b} // List(3,7)
val a = list.map(_.split(','))
// the above is a shorthand for
val a = list.map({ case i => i.split(',') })
// Now lets consider this
val a = list.map { case (a, b) => a + b }
// or this
val a = list map { case (a, b) => a + b }
// some people like the above ways of writing
// because they consider of less brackets as cleaner code.
// but the above two are another way to write
val a = list.map({ case (a, b) => a + b })
The thing to understand here is that in Scala you can use spaces instead of . to access instance methods.
So basically,
// lets say you have a class A
case class A(i: Int) {
def merged[B](b: B): String = i.toString + " :: " + b.toString
}
//Now, lets say you have an instance of A
val a = A(5)
// and an instance of String
val s: String = "abcd"
// Now, if you write
val merged = a merged s
// it is syntactic sugar for
val merged = a.merged(s)
Similarly, List[A] has a method map[B](f: A => B): List[B].
val list = List[Int](1, 2, 3)
// so when you write
val list2 = list map { case i => i + 1}
// its syntactic sugar for,
val list2 = list.map({ case i => i + 1 })
// There is a lot going on here
// if we were to do everything step by step
// first you are creating a partial function
val pf: PartialFunction[Int, Int] = { case i => i + 1 }
// Now, PartialFunction[Int, Int] is a subtype of Int => Int
// so we can refer to it as a Int => Int
val f: Int => Int = pf
// Now we pass it as an argument to map
val list2 = list.map(f)
i am new to scala and got stuck with one pattern matching case.
i am writing a pattern match as below,
case class data(record:String)
def x(input:String)= input match {
case "a" => val a = data("a")
case "b" => val b = data("b")
case anythingElse = val others = ...other object creation
}
i would like to access the variables val a,val b and val others outside of the def x.
is there a way to return val a, val b and val others once the calls to the def x is completed.
Your understanding of pattern matching is not entirely correct, you can assign vals in each case area, but the only purpose of that would be to do something temporary. In scala whatever statement you place last is the return value. This cannot be a val assignment statement, or no value (aka unit) would be returned
def x(input:String)= input match {
case "a" => data("a and something special")
case "b" =>
val temp = "b"+" Hello"
data(temp)
case other => data(other)
}
To my understanding, you are trying to define a new variable in a scope that is outside of each case block:
case class data(record:String)
def x(input:String)= input match {
case "a" => val a = data("a")
case "b" => val b = data("b")
case anythingElse = val others = ...other object creation
}
x("a")
println(a) // should print data("a")
Correct?
That is not going to work! Because Scala "Cannot resolve symbol a". It wasn't defined in the scope where you are using it.
Instead you could propagate it to outer scope using some kind of a data container ( defined in the outer scope ). It could be an array, a variable, or a Map. However this will also make it a mutable container. Not recommended.
A better approach would be to actually return your state from x() method and then use that state. Something like this:
case class Data(record: String)
val template: Map[String, Option[Data]] = List("a", "b", "c").map(_ -> None).toMap[String, Option[Data]]
def x(input: String): Map[String, Option[Data]] = input match {
case "a" => template + ("a" -> Some(Data("a")))
case "b" => template + ("b" -> Some(Data("b")))
case anythingElse => template + ("others" -> Some(Data("others")))
}
val returnMap = x("a")
for (x <- returnMap("a")) {
println(x)
}
OUTPUT:
Data(a)
Values a, b and others are local to each case; consider though
def x(input:String)= input match {
case "a" => (Some(data("a")), None, None)
case "b" => (None, data("b"), None)
case anythingElse = (None, None, `...other object creation`)
}
where the function returns a triplet of Option in which a None represents no matching, and Some(data("...")) a match; hence for instance
val (a,b,others) = x("a")
delivers
a = Some(data("a"))
b = None
others = None
Suppose I have 2 methods:
def a(s: String) = s + "..."
def b(s: String) = s + ",,,"
And I want to create 3rd method which will call both methods:
def c (s: String) = a(b(s))
How I can do it in idiomatic Scala way?
I think it's better to aggregate this functions into some List and then sequentially apply them:
List(a_, b_)
I think it's better to aggregate this functions into some List and
then sequentially apply them.
You get some help by specifying an expected type:
scala> val fs: List[String => String] = List(a,b)
fs: List[String => String] = List(<function1>, <function1>)
scala> fs.foldLeft("something")((s,f) => f(s))
res0: String = something...,,,
Here is how you can combine a set of functions into one:
// a() and b() are as defined in the question
// the following is equivalent to newfunc(x) = b(a(x))
val newFunc: String => String = List( a _, b _).reduce( _ andThen _ )
You can even create a generic function to combine them:
def functionChaining[A]( functions: A => A *): A => A = functions.reduce( _ andThen _ )
or using foldLeft:
def functionChaining[A]( functions: A => A *): A => A = functions.foldLeft( (x:A) => x )( _ andThen _ )
Here is an example of how to use this on the REPL:
scala> val newFunc: String => String = functionChaining( (x:String) => x + "---", (x:String) => x * 4)
scala> newFunc("|")
res12: String = |---|---|---|---
Many answers use andThen, but that will be give you
b(a(s))
Given that you want
a(b(s))
compose is the way to go (well, that or reversing the list, but what's the point?)
def c(s: String) = List[String => String](a, b).reduce(_ compose _)(s)
// or alternatively
def c(s: String) = List(a _, b _).reduce(_ compose _)(s)
As a result
c("foo") // foo,,,...
Now, speaking of what's idiomatic, I believe that
a(b(s))
is more idiomatic and readable than
List(a _, b _).reduce(_ compose _)(s)
This clearly depends on the number of functions you're composing. If you were to have
a(b(c(d(e(f(g(h(s))))))))
then
List[String => String](a, b, c, d, e, f, g, h).reduce(_ compose _)(s)
is probably neater and more idiomatic as well.
If you really think you need to do this:
val c = a _ andThen b
// (The signature is:)
val c:(String)=>String = a _ andThen b
or, more obviously:
def d(s:String) = a _ andThen b
If chained application is preferred then the below works. Caveats - Implicit syntax is a bit ugly; This being a structural type uses reflection.
object string {
implicit def aPimp(s: String) = new {
def a = "(a- " + s + " -a)"
}
implicit def bPimp(s: String) = new {
def b = "(b- " + s + " -b)"
}
}
scala> import string._
scala> "xyz".a.b
res0: String = (b- (a- xyz -a) -b)
scala> "xyz".b.a
res1: String = (a- (b- xyz -b) -a)
In my opinion, if not for the ugly syntax, this would be idiomatic scala.
I have a code such as:
val strs = List("hello", "andorra", "trab", "world")
def f1(s: String) = !s.startsWith("a")
def f2(s: String) = !s.endsWith("b")
val result = strs.filter(f1).filter(f2)
now, f1 and f2 should be applied based on a condition, such as:
val tmp1 = if (cond1) strs.filter(f1) else strs
val out = if (cond2) tmp1.filter(f2) else tmp1
is there a nicer way to do this, without using a temporary variable tmp1?
one way would to filter based on a list of functions, such as:
val fs = List(f1 _,f2 _)
fs.foldLeft(strs)((fn, list) => list.filter(fn))
but then I would need to build a list of functions based on the conditions (and so, I would move the problem of using a temporary string list variable, to using a temporary function list variable (or I should need to use a mutable list)).
I am looking something like this (of course this does not compile, otherwise I would already have the answer to the question):
val result =
strs
.if(cond1, filter(f1))
.if(cond2, filter(f2))
You could use an implicit class to give you this syntax:
val strs = List("hello", "andorra", "trab", "world")
def f1(s: String) = !s.startsWith("a")
def f2(s: String) = !s.endsWith("b")
val cond1 = true
val cond2 = true
implicit class FilterHelper[A](l: List[A]) {
def ifFilter(cond: Boolean, f: A => Boolean) = {
if (cond) l.filter(f) else l
}
}
strs
.ifFilter(cond1, f1)
.ifFilter(cond2, f2)
res1: List[String] = List(hello, world)
I would have used if as the method name but it's a reserved word.
You can do this by summing your predicate functions.
Observe that a filter predicate, A => Boolean, has an append operation:
def append[A](p1: A => Boolean, p2: A => Boolean): A => Boolean =
a => p1(a) && p2(a)
And an identity value:
def id[A]: A => Boolean =
_ => true
which satisfies the condition that for any predicate p: A => Boolean, append(p, id) === p.
This simplifies the problem of including/excluding a predicate based on a condition: if the condition is false, simply include the id predicate. It has no effect on the filter because it always returns true.
To sum the predicates:
def sum[A](ps: List[A => Boolean]): A => Boolean =
ps.foldLeft[A => Boolean](id)(append)
Note that we fold onto id, so if ps is empty, we get the identity predicate, i.e. a filter that does nothing, as you'd expect.
Putting this all together:
val predicates = List(cond1 -> f1 _, cond2 -> f2 _)
strs.filter(sum(predicates.collect { case (cond, p) if cond => p }))
// List(hello, world)
Note that the list strs was only traversed once.
Now, for the Scalaz version of the above:
val predicates = List(cond1 -> f1 _, cond2 -> f2 _)
strs filter predicates.foldMap {
case (cond, p) => cond ?? (p andThen (_.conjunction))
}
// List("hello", "world")
#Noah's answer is good, and you can take it and generalize it further if you want to be able to perform any type of action on a list then returns a new List given a condition if you make the following change:
implicit class FilterHelper[A](l: List[A]) {
def ifthen[B](cond: Boolean, f:(List[A]) => List[B]) = {
if (cond) f(l) else l
}
}
Then use it like this:
val list = List("1", "2")
val l2 = list.ifthen(someCondition, _.filter(f1)
val l3 = list.ifthen(someOtherCondition, _.map(_.size))
It would be rather simple to just include the condition in your block for the filter, like so:
val result = strs filter (x => !cond1 || f1(x)) filter (x => !cond2 || f2(x))
whereby the result would apply a filter if the condition is met, or simply return the same list.