Reading Lines from Sample Code in 'Programming in Scala' - scala

Working through a sample in Chapter 3 of "Programming in Scala", the following code doesn't seem working on Scala 2.8:
import scala.io.Source
if (args.length > 0) {
for (line <- Source.fromFile(args(0)).getLines)
print(line.length + " " + line)
}
else
Console.err.println("Filename required.")
Scala complains fromFile is expecting type java.io.File. With a bit of searching it seems that I should be using fromPath instead...
for (line <- Source.fromPath(args(0)).getLines)
However, I now get a puzzling error from that (puzzling to a beginner anyways):
... :4: error: missing arguments for method getLines in class Source;
follow this method with `_' if you want to treat it as a partially applied function
Error occurred in an application involving default arguments.
for (line <- Source.fromPath(args(0)).getLines)
^
one error found
I took a guess at trying...
for (line <- Source.fromPath(args(0)).getLines _)
And that didn't work. What's the Scala 2.8 way of making getLines work?

The signature of getLines is this:
def getLines(separator: String = compat.Platform.EOL): Iterator[String] = new LineIterator(separator)
So it has a default argument. You need to write getLines() instead, so that this default will be used.

Related

Scala type mismatch from Java library

I am trying to use a Java library (Hipster) with Scala. Running the example on the front page, I get this type error message which I can't make sense of:
My attempt so far was to try convert Java <==> Scala Doubles and Strings to no avail.
<console>:23: error: type mismatch;
found : es.usc.citius.hipster.model.problem.SearchProblem[scala.Double,String,es.usc.citius.hipster.model.impl.WeightedNode[scala.Double,String,java.lang.Double]]
required: es.usc.citius.hipster.model.problem.SearchProblem[A,S,N]
val sol = Hipster.createDijkstra(pX)
Code sample:
import es.usc.citius.hipster.algorithm.Hipster
import es.usc.citius.hipster.model.problem.SearchProblem
val graph = GraphBuilder.create[String,Double]().connect(
"A").to("B").withEdge(4.0).
connect("A").to("C").withEdge(2.0).
connect("B").to("C").withEdge(5.0).
connect("B").to("D").withEdge(10.0).
connect("C").to("E").withEdge(3.0).
connect("D").to("F").withEdge(11.0).
connect("E").to("D").withEdge(4.0).
createDirectedGraph()
// Create the search problem. For graph problems, just use
// the GraphSearchProblem util class to generate the problem with ease
val pX = GraphSearchProblem.startingFrom("A").in(graph).takeCostsFromEdges().build();
// Search the shortest path from "A" to "F"
val sol = Hipster.createDijkstra(pX)

for comprehension with tuple, withFilter is not a member error

The following code snippet
import util.control.TailCalls._
for {(num, ch) <- done((3, '3'))
} yield num
fails to compile with error message:
value withFilter is not a member of util.control.TailCalls.TailRec[(Int, Char)]
I am using Scala 2.12.7. How to avoid this error? (IntelliJ Idea 18.3.1 with Scala plugin v2018.3.4 does not show error.)
To avoid the call to withFilter and keep the current syntax, it helps if a compiler plugin is used to treat for comprehensions differently. An option is using better-monadic-for.
Adding this to the build.sbt file should make the code in the question compile:
addCompilerPlugin("com.olegpy" %% "better-monadic-for" % "0.3.0-M4")
(Though it has other -usually positive- effects too, please check its documentation.)
Another option is implementing withFilter with an extension method, for example like this (and having it in scope at usage site):
implicit class TailCallsExtension[A](t: TailRec[A]) {
def withFilter(pred: A => Boolean): TailRec[A] = t.flatMap(a => if (pred(a)) t else done(a))
}
Seemingly there is no filtering in the code, but actually the pattern match in Scala for comprehensions (before <-) are translated as a call to withFilter. TailCalls does not support withFilter, so this will not compile. The following rewrite compiles though:
import util.control.TailCalls._
done((3, '3')).map{ case (num, ch) => num}

Uses of _ in Scala

I am new to Scala and was trying to understand where we can use underscore and where Scala prevents the use of underscore. I read through various posts but I am not able to completely understand the concept. I would appreciate any help on this. Thanks
Code:
object ScalaMainObj {
def main(args : Array[String])
{
val t1 = List(1,2,3,4)
//t1.foreach(println(_*2)) -> Will refer to this as Line1
//t1.foreach(_*2) -> Will refer to this as Line2
t1.foreach(x => println(x*2)) //-> Will refer to this as Line3
}
Question:
I am trying to understand why code in Line1 gives me an error while compiling. The error I get is "missing parameter type for expanded function ((x$1) ⇒ x$1.$times(2))"
Does the above statement indicate that scala is not able to resolve the return type of (x$1 * 2) function?
Since the code in Line2 is compiling, I believe that scala is able to resolve the type of '_'as Int. (Tried to replace * function with / function since "/" function is available to Int and not Strings)
Thanks again for any suggestions/explanations

Deal with Java NIO Iterator in Scala with Try

I recently learned how to use Scala's native Try type to handle errors. One good thing with Try is that I'm able to use for-comprehension and silently ignore the error.
However, this becomes a slight problem with Java's NIO package (which I really want to use).
val p = Paths.get("Some File Path")
for {
stream <- Try(Files.newDirectoryStream(p))
file:Path <- stream.iterator()
} yield file.getFileName
This would have been perfect. I intend to get all file names from a directory, and using a DirectoryStream[Path] is the best way because it scales really well. The NIO page says DirectoryStream has an iterator() method that returns an iterator. For Java's for loop, it's enough and can be used like this:
try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
for (Path file: stream) {
System.out.println(file.getFileName());
}
}
However, Scala does not accept this. I was greeted with the error:
[error] /.../DAL.scala:42: value filter is not a member of java.util.Iterator[java.nio.file.Path]
[error] file:Path <- stream.iterator
I try to use JavaConverters, and it shows it handles Java Iterator type: scala.collection.Iterator <=> java.util.Iterator, but when I try to call it in this way: stream.iterator().asScala, the method is not reachable.
What should I do? How do I write nice Scala code while still using NIO package?
I don't actually quite get while in this for comprehension filter is being invoked, but note that stream.iterator() returns a Iterator[Path], not a Path, even though my IDE thinks it does, probably because he thinks he can apply map to it, but in truth this are methods which are not defined on java.util.Iterator[java.nio.file.Path] as the compiler confirms:
scala> for {
| stream <- Try(Files.newDirectoryStream(p))
| file <- stream.iterator()
| } yield file
<console>:13: error: value map is not a member of java.util.Iterator[java.nio.file.Path]
file <- stream.iterator()
This for comprehension translates to:
Try(Files.newDirectoryStream(p)).flatMap(stream => stream.iterator().map(...))
Where the second map is not defined. One solution could be found in this SO question, but I can't tell you how to use iterator in for comprehension here since in java iterator cannot be mapped on and I'm not sure you can convert it into the comprehension.
Edit:
I managed to find out more about the problem, I tried this for comprehension:
for {
stream <- Try(Files.newDirectoryStream(p))
file <- stream.iterator().toIterator
} yield file
This doesn't compile because:
found : Iterator[java.nio.file.Path]
required: scala.util.Try[?]
file <- stream.iterator().toIterator
It translates to:
Try(Files.newDirectoryStream(p)).flatMap(stream => stream.iterator().map(...))
But flatMap actually expects a Try back, in fact this works:
Try(Files.newDirectoryStream(p)).flatMap(stream => Try(stream.iterator().map(...)))
^
What I came up with:
import java.nio.file.{Paths, Files}
import util.Try
import scala.collection.JavaConversions._
Try(Files.newDirectoryStream(p))
.map(stream =>
stream
.iterator()
.toIterator
.toList
.map(path => path.getFileName.toString)
).getOrElse(List())
Which returns a List[String], unfortunately this is far from being as pretty as your for comprehension, maybe somebody else has a better idea.
I really like what Ende Neu wrote and it's hard to work with NIO in Scala. I want to preserve the efficiency brought from Java's Stream, so I decide to write this function instead. It still uses Try and I only need to deal with Success and Failure cases :)
It's not as smooth as I'd hope, and without Java 7's great try-with-resource feature, I have to close the stream by myself (which is terrible...), but this works out.
def readFileNames(filePath: String):Option[List[Path]] = {
val p = Paths.get(filePath)
val stream: Try[DirectoryStream[Path]] = Try(Files.newDirectoryStream(p))
val listOfFiles = List[Path]()
stream match {
case Success(st) =>
val iterator = st.iterator()
while (iterator.hasNext) {
listOfFiles :+ iterator.next()
}
case Failure(ex) => println(s"The file path is incorrect: ${ex.getMessage}")
}
stream.map(ds => ds.close())
if(listOfFiles.isEmpty) None else Some(listOfFiles)
}

Missing Parameter Type For Expanded Function

I am new to Scala and I am having trouble with an example from the book Scala in Action.
I am using IntelliJ, but I've also tried it as script (REPL). The scala compiler gives me the same error as IntelliJ. (I am using Scala 2.10, as the book suggest).
Here is my code:
def parseArgs(args: Array[String]): Map[String, List[String]] = {
val command = args.head
val params = parseArgs(args)
val url = args.last
def nameValuePair(paramName: String) = {
def values(commaSeparatedValues: String) = commaSeparatedValues.split(",").toList
// x => x + 2
val index = args.indexOf(_ == paramName)
(paramName, if(index == -1) Nil else values(args(index + 1)))
}
Map(nameValuePair("-d"), nameValuePair("-h"))
}
The message I get is:
C:\scala\projects\scripts\restclientscript.scala:12: error: missing parameter type for expanded function ((x$1) => x$1.$eq$eq(paramName))
val index = args.indexOf(_ == paramName)
^
one error found
This is exactly as it is shown in the book but I can't figure out how to make it work.
Also the method indexOf is actually findIndexOf in the book. But that method does not exist the compiler tells me (and the doc: http://www.scala-lang.org/api/2.10.3/index.html#scala.Array).
Lastly, IntelliJ will not accept the == inside the indexOf() method (highlighted red, but compiles).
Any help would be appreciated! :)
The book may be referring to an older version of Scala. Looking at the doc page you linked it is clear that the method indexOf has the following signature:
indexOf(elem: T): Int
That means that the method doesn't expect a closure but instead a value. You probably want to use indexWhere:
indexWhere(p: (T) ⇒ Boolean): Int
That should work!
One more advice is: never trust IntelliJ Idea errors, always double check them with sbt as Idea uses a different algorithm for checking errors and doesn't rely on the actual compiler.
Array.indexOf takes an instance for which the index should be found in the array.
If you want a version with predicate, there's Array.indexWhere (at least according to Scala 2.11 docs) which takes a predicate function p : (T) => Boolean.
So, you can either do:
args.indexOf(paramName)
or
args.indexWhere(_ == paramName)