Here are my notes on learning Scala:
- Not a lot of tool support yet. JEdit syntax highlighting works OK, as do some other editors. Eclipse plugin provides more capability, but it is slow.
- Environment variables:
- SCALA_HOME=/path/to/scala/dir
- PATH (add $SCALA_HOME/bin)
-
Notes on the language proper:
Hello World:
object HelloWorld {
def main(args: Array[String]) {
println("Hello, world!")
}
}
object defines a singleton class instance. Every program has a function named main inside a singleton object.
def defines a function or an expression without evaluating it; it does not evaluate its RHS.
Val defines a constant; it evaluates its RHS.
Formal parameter definition should always include a type. (Array[String] for the main function.)
Function calls are call-by-value by default. Formal parameters with ": =>" instead of just ":" are call-by-name.
Every statement returns a value.
"return val" is the same as "val" at the end of a function.
Semicolons may be used as statement terminators.
Function definitions look like this:
def funcname(parm: ParmType):FuncType = { statements; }
You can omit the surrounding {} if the function body is a single statement.
You can omit FuncType if it is obvious to the compiler.
Conditions (e.g. in an if-statement) must be surrounded by parenthesis, as in C and Java.
You can nest functions (in order to scope the names).
Tail-recusion is optimized for "directly tail-recursive" calls. e.g. This gets optimized:
def gcd(a: Int, b: Int): Int = if (b == 0) a else gcd(b, a % b)
... but this does not (due to the need to multiply AFTER the recursion returns).
def factorial(n: Int): Int = if (n == 0) 1 else n * factorial(n 1)
Named functions can be passed by name too ("First-class functions"), as can anonymous functions.
Here is an anonymous function in use:
def blarfle(a: Int, b: Int): Int = sum((x: Int) => x * x, a, b)
The function header is "(x: Int)", so it is a function that takes a single, integer parameter. The body of the function is "x * x".
Sometimes you can get away with omitting the type (if the compiler can figure it out), as in:
def blarfle(a: Int, b: Int): Int = sum((x) => x * x, a, b)
And, whenever your argument list is just "(x)" it can be rewritten as "x" giving:
def blarfle(a: Int, b: Int): Int = sum(x => x * x, a, b)
Sometimes you'll run into a function that looks like this:
def sum(f: Int => Int): (Int, Int) => Int = { def sumF(a: Int, b: Int): Int = if (a > b) 0 else f(a) + sumF(a + 1, b) sumF }
This says that 'sum' is a function that take a function (the argument 'f') that takes an Int parameter and returns an Int result;], and the function 'sum' returns a function of type "(Int, Int)=> Int)". In other words, 'sum' is a function factory that takes one function as its argument, and it generates a function that takes two Ints (and returns an Int).
One way to use sumF would be to do something like:
def g = sum((x) => x * x) g(1,3)
... which calls 'sum' to generate a function that sums squares, naming the new function 'g', and then calls 'g' with 1 and 3 as parameters.
Sometimes Scala can't really tell that this is what you are trying to do, and it complans in your def of g. You solve that problem like so:
def g = sum((x) => x * x) _ g(1,3)
... which uses the trailing underscore to tell Scala, "Hey! Don't worry -- this call of 'sum' just returns a function and I promise to pass the right arguments to that function when I call it. (I think.)
<pFor the ultimate in brevity, you can define g and call it in a single line:</p>
sum(x => x * x)(1, 10)
The "sum(x => x * x)" generates the new (unnamed) function and the "(1, 10)" calls it with the arguments 1 and 10.
more soon