Scala parser combinator reduce/foldLeft - scala

I'm trying to make the following, from a dynamically filled List:
val primitives = "x" | "y" | "z" // what I want
val primitives2 = List("x", "y", "z") // what I need to transform from
I figured something like this might work:
primitives2.reduce(_|_)
But no go. I then found this snippet, which works:
primitives2.foldRight(failure("no matching delimiter"): Parser[Any])(_|_)
However, the base case failure("no matching delimiter") is confusing. Is that just the equivalent Nil case for Parser objects?

I'm going to assume that you're working with RegexParsers or one of its descendants. If so, then the issue is just that the implicit conversion from String to Parser[String] won't kick in automatically with reduce(_ | _). If you explicitly convert every item in your list first, like this:
val anyPrimitive = primitives2.map(literal).reduce(_ | _)
You'll be perfectly fine—except that this will leave you with slightly confusing error messages, like this:
scala> parser.parseAll(parser.anyPrimitive, "a")
res8: parser.ParseResult[Any] =
[1.1] failure: `z' expected but `a' found
a
^
If you want a clearer error message, then you'll need to provide your own starting value using the fold approach.

Related

Scala: do something if get the value in getOrElse

If a variable is an Option[Account], and there is a string field called accountName in the class Account.
e.g:
val allAccounts: Set[Option[Account]] = Set(Some(Account1), Some(Account2), None)
How do I get the accountName from Some(Account) if I get something from getOrElse?
I tried allAccounts.map(_.getOrElse("").accountName) but it doesn't work. It cannot apply to the "get" part but the "OrElse" part
Thanks for your help!
PS: wonder why allAccounts.map(_.map(_.accountName).getOrElse("")) works fine with None value but if I create another variable: val sampleAccount2 = None and sampleAccount2.map(_.accountName).getOrElse("") will failed? Basically I just goes from Set(None) to None ?
Is this what you ultimately wanted to achieve?
final case class Account(accountName: String)
val allAccounts: Set[Option[Account]] =
Set(Some(Account("Account1")), Some(Account("Account2")), None)
def getAccountNames(maybeAccounts: Set[Option[Account]]): Set[String] =
maybeAccounts.map(_.fold("")(_.accountName))
assert(getAccountNames(allAccounts) == Set("Account1", "Account2", ""))
You can play around with this code here on Scastie.
Another way to write getAccountNames is by using a combination of map and getOrElse instead of fold, like so:
def getAccountNames(maybeAccounts: Set[Option[Account]]): Set[String] =
maybeAccounts.map(_.map(_.accountName).getOrElse(""))
This is probably closer to what you initially wanted to write. In this case fold and map with getOrElse are basically equivalent, choose whichever makes more sense given your knowledge of the code base you're working on at the moment.
This version is also available here on Scastie.
The problem with your attempt if that you were applying getOrElse to the Option[Account] type, meaning that you were trying to return something that was either an Account (within the Option) or a String and from that thing you were then asking the accountName, which only makes sense on Account but not on String. The key difference is that in this case you first map on Option[Account] to get the accountName on Somes, getting an Option[String], and then you either get what's in there or the default value if the Option is empty.
As further input, please note that since you are using a Set, if you have multiple empty values in your input, they will be effectively collapsed into one, as in the following example:
assert(getAccountNames(Set(None, None)) == Set(""))
If by any chance you would rather remove any empty value entirely from the output, you can do so by rewriting the function above so that it's defined like so (Scastie):
def getAccountNames(maybeAccounts: Set[Option[Account]]): Set[String] =
maybeAccounts.flatMap(_.map(_.accountName))
In this case getAccountNames can be redefined in terms of a for-comprehension (more on the topic here on the Scala documentation):
def getAccountNames(maybeAccounts: Set[Option[Account]]): Set[String] =
for {
maybeAccount <- maybeAccounts
account <- maybeAccount
} yield account.accountName
This last example is also available here on Scastie for you to play around with it.
In both cases, the assertion that holds now changes to the following:
assert(getAccountNames(allAccounts) == Set("Account1", "Account2"))

Read a tuple from a file in Scala

my Task is to read registrations from a file given like:
Keri,345246,2
Ingar,488058,2
Almeta,422016,1
and insert them into a list(Tuple of (String, Int, Int).
So far I wrote this:
The problem is that I don‘t understand why I can't try to cast value2 and value3 to Int even tho they should be Strings because they come from an Array of Strings. Could someone tell me, what my mistake is, I am relatively new to Scala
What is the point of using Scala if you are going to write Java code?
This is how you would properly read a file as a List of case classes.
import scala.io.Source
import scala.util.Using
// Use proper names for the fields.
final case class Registration(field1: String, field2: Int, field3: Int)
// You may change the error handling logic.
def readRegistrationsFromFile(fileName: String): List[Registration] =
Using(Source.fromFile(fileName)) { source =>
source.getLines().map(line => line.split(',').toList).flatMap {
case field1Raw :: field2Raw :: field3Raw :: Nil =>
for {
field2 <- field2Raw.toIntOption
field3 <- field3Raw.toIntOption
} yield Registration(field1 = field1Raw.trim, field2, field3)
case _ =>
None
}.toList
}.getOrElse(default = List.empty)
(feel free to ask any question you may have about this code)
In Scala, in order to convert a String to an Int you need explicit casting.
This can be achieved like this if you are sure the string can be parsed into a integer:
val values = values(1).toInt
If you cannot trust the input (and you probably should not), you can use .toIntOption which will give you a Option[Int] defined if the value was converted successfully or undefined if the string did not represent an integer.
The previous answers are correct. I would add a few more points.
saveContent is declared as a val. This is means it cannot be changed (assigned another value). You can use the Scala REPL (command-line) tool to check:
scala> val saveContent = Nil
val v: collection.immutable.Nil.type = List()
scala> saveContent = 3
^
error: reassignment to val
Instead, you could use a var, although it would be more idiomatic to have an overall pattern like the one provided by Luis Miguel's answer - with pattern-matching and a for-comprehension.
You can use the Scala REPL to check the types of the variables, too. Splitting a String will always lead to more Strings, not Ints, etc.
> val values = "a,2,3".split(",")
val values: Array[String] = Array(a, 2, 3)
> values(2)
val res3: String = 3
This is why a cast like Gael's is necessary.
Array-type access is done with parentheses and not square brackets, in Scala. See above, and http://scalatutorials.com/tour/interactive_tour_of_scala_lists for more details.

What is the meaning of "val Class.Something(2,_) = doSomething()"?

I am reading Lihaoyi's presentation of his parser combinators framework while knowing only the basics of Scala.
I came across this line that I don't understand at all:
val Parsed.Success(2, _) = parse("1+1", expr(_))
Coming from Java, it looks weird. Anybody knows what it does?
Thanks in advance.
https://www.lihaoyi.com/fastparse/
What would be the equivalent in Java?
Scala knows Extractor Objects - see docs.scala-lang.org
They are mostly used for pattern matching - see docs.scala-lang.org
So this can be used with vals:
val customer2ID = CustomerID("Nico")
val CustomerID(name) = customer2ID
println(name) // prints Nico
Your example will throw a scala.MatchError if the parser would not work.
Try val Parsed.Success(2, _) = parse("1+2", expr(_)) // should be 3
Other answers explained what this is technically, but why did the author of fastparse write
val Parsed.Success(2, _) = parse("1+1", expr(_))
where we see no variable is actually bound in the sense of being usable after this statement executes? This kind of looks like a side-effect returning unit. I believe the author is deploying this technique as an alternative to assertion
assert(parse("1+1", expr(_)) == Parsed.Success(2, 3))
but they want to emphasise they do not care about the index value of Success[+T](value: T, index: Int) which they cannot do using regular assert
assert(parse("1+1", expr(_)) == Parsed.Success(2, _)) // error: missing parameter type for expanded function
Function parse is returning a Parsed[T], which is matched against the extractor of the Success case class (inside the object Parsed).
It could be rewritten as:
parse("1+1", expr(_)) match {
case Parsed.Success(2, _/*index*/) => ???
}
The previous make it obvious that it's not an exhaustive match (and so the val pattern would raise a MatchError).
Could also be used as bellow, to be more explicit and avoid MatchError.
val res: Option[(Int/* value */, Int/* index */)] =
Parsed.Success.unapply(parse("1+2", expr(_)))

Scala parser-combinators: how to invert matches?

Is it possible to invert matches with Scala parser combinators? I am trying to match lines with a parser that do not start with a set of keywords. I could do this with an annoying zero width negative lookahead regular expression (e.g. "(?!h1|h2).*"), but I'd rather do it with a Scala parser. The best I've been able to come up with is this:
def keyword = "h1." | "h2."
def alwaysfails = "(?=a)b".r
def linenotstartingwithkeyword = keyword ~! alwaysfails | ".*".r
The idea is here that I use ~! to forbid backtracking to the all-matching regexp, and then continue with a regex "(?=a)b".r that matches nothing. (By the way, is there a predefined parser that always fails?) That way the line would not be matched if a keyword is found but would be matched if keyword does not match.
I am wondering if there is a better way to do this. Is there?
You can use not here:
import scala.util.parsing.combinator._
object MyParser extends RegexParsers {
val keyword = "h1." | "h2."
val lineNotStartingWithKeyword = not(keyword) ~> ".*".r
def apply(s: String) = parseAll(lineNotStartingWithKeyword, s)
}
Now:
scala> MyParser("h1. test")
res0: MyParser.ParseResult[String] =
[1.1] failure: Expected failure
h1. test
^
scala> MyParser("h1 test")
res1: MyParser.ParseResult[String] = [1.8] parsed: h1 test
Note that there is also a failure method on Parsers, so you could just as well have written your version with keyword ~! failure("keyword!"). But not's a lot nicer, anyway.

Scala Map#get and the return of Some()

Im using scala Map#get function, and for every accurate query it returns as Some[String]
IS there an easy way to remove the Some?
Example:
def searchDefs{
print("What Word would you like defined? ")
val selection = readLine
println(selection + ":\n\t" + definitionMap.get(selection))
}
When I use this method and use the following Input:
What Word would you like defined? Ontology
The returned Value is:
Ontology:
Some(A set of representational primitives with which to model a domain of knowledge or discourse.)
I would like to remove the Some() around that.
Any tips?
There are a lot of ways to deal with the Option type. First of all, however, do realize how much better it is to have this instead of a potential null reference! Don't try to get rid of it simply because you are used to how Java works.
As someone else recently stated: stick with it for a few weeks and you will moan each time you have to get back to a language which doesn't offer Option types.
Now as for your question, the simplest and riskiest way is this:
mymap.get(something).get
Calling .get on a Some object retrieves the object inside. It does, however, give you a runtime exception if you had a None instead (for example, if the key was not in your map).
A much cleaner way is to use Option.foreach or Option.map like this:
scala> val map = Map(1 -> 2)
map: scala.collection.immutable.Map[Int,Int] = Map(1 -> 2)
scala> map.get(1).foreach( i => println("Got: " + i))
Got: 2
scala> map.get(2).foreach( i => println("Got: " + i))
scala>
As you can see, this allows you to execute a statement if and only if you have an actual value. If the Option is None instead, nothing will happen.
Finally, it is also popular to use pattern matching on Option types like this:
scala> map.get(1) match {
| case Some(i) => println("Got something")
| case None => println("Got nothing")
| }
Got something
I personally like using .getOrElse(String) and use something like "None" as a default i.e. .getOrElse("None").
I faced similar issue, replaced with .Key() to resolve.
Solution:
definitionMap(selection)
In modern scala you can just map(key)