Scala: first impressions
Posted: Thu Sep 18, 2014 3:18 pm
I needed to parse an XML file to produce an output file yesterday, so I decided to use Scala as an exercise in learning it.
The good news was I didn't have to install anything but `apt-get install scala` and an Emacs package manager (!) so I could grab a Scala mode Emacs package. The base capabilities of the language were plenty for this little toy. The other good news is that it runs 100x faster than the piece of software (graphviz) which consumes the output, so it is by definition sufficiently fast (10-20 seconds on a 6.6MB input, depending on the compilation time).
The ugly:
Having a compiler barf at you when you do something stupid is pretty great, but the errors are very non-intuitive. Also, at first I pretty consistently generated a runtime error on a .toDouble call, the text of which was zero help.
The syntax for creating tuples is simple and "right". The syntax for consuming tuples as arguments to functions seems backasswards. I'm still not convinced there isn't a more elegant way to do it lurking somewhere in the language, but I couldn't find it while drinking a Double Mountain IRA last night.
The abomination that is the }) really needs to be dragged out into the street and hanged.
At first I tried producing my output with a map, but evidently that is a no-no. Something about side effects? Not sure.
I would have never in a thousand years come up with that XML parsing syntax, but it's starting to grow on me. I worry about how expensive it is.
ToDo:
I need to control the number of digits printed out in the label.
I need to limit the number of taillabels to the number of systems.
Code: Select all
import scala.xml._
import scala.math._
object HelloWorld {
def main(args: Array[String]) {
println("graph New_Eden {");
println(" node [shape=point];");
val xml = XML.loadFile("/home/jonathan/Downloads/mapsolarsystems.xml")
val records = (xml \\ "RECORDS" \\ "RECORD").filter(x => (x \ "securityClass").text != "")
val systems = records.map( x => ((x \ "solarSystemName").text, (x \ "x").text.toDouble, (x \ "y").text.toDouble, (x \ "z").text.toDouble))
val output = systems.map(base => {
val name = base._1
val x = base._2
val y = base._3
val z = base._4
(name, (systems
.filter(subrecord =>
name != subrecord._1)
.map(pair => {
val x2 = pair._2
val y2 = pair._3
val z2 = pair._4
(pair._1, sqrt(pow(x-x2,2)+pow(y-y2,2)+pow(z-z2,2))/(9.4605284*pow(10,15)))
}).filter(outrec =>
outrec._2 <= 2.0)
))
})
output.foreach(r => {
r._2.foreach(A => {
println("\"" + r._1 + "\" -- \"" + A._1 + "\" [label=" + A._2 + " headlabel=\"" + A._1 + "\" len=" + A._2 + "];")
})
})
println("}");
}
}
The ugly:
Having a compiler barf at you when you do something stupid is pretty great, but the errors are very non-intuitive. Also, at first I pretty consistently generated a runtime error on a .toDouble call, the text of which was zero help.
The syntax for creating tuples is simple and "right". The syntax for consuming tuples as arguments to functions seems backasswards. I'm still not convinced there isn't a more elegant way to do it lurking somewhere in the language, but I couldn't find it while drinking a Double Mountain IRA last night.
The abomination that is the }) really needs to be dragged out into the street and hanged.
At first I tried producing my output with a map, but evidently that is a no-no. Something about side effects? Not sure.
I would have never in a thousand years come up with that XML parsing syntax, but it's starting to grow on me. I worry about how expensive it is.
ToDo:
I need to control the number of digits printed out in the label.
I need to limit the number of taillabels to the number of systems.