A huge re-organization of the Scala file

This commit is contained in:
Geoff Liu 2014-11-10 19:24:00 -07:00
parent 459967e446
commit 57c9f70417

View File

@ -4,6 +4,7 @@ filename: learnscala.scala
contributors:
- ["George Petrov", "http://github.com/petrovg"]
- ["Dominic Bou-Samra", "http://dbousamra.github.com"]
- ["Geoff Liu", "http://geoffliu.me"]
filename: learn.scala
---
@ -20,16 +21,16 @@ Scala - the scalable language
scala>
This is the so called REPL. You can run commands in the REPL. Let's do just
that:
This is the so called REPL (Read-Eval-Print Loop). You may type any valid
Scala expression into it, and the result will be printed. We will explain what
Scala files look like further into this tutorial, but for now, let's start
with some basics.
*/
println(10) // prints the integer 10
println("Boo!") // printlns the string Boo!
// Some basics
#################################################
## 1. Basics
#################################################
// Printing, and forcing a new line on the next print
println("Hello world!")
@ -37,15 +38,15 @@ println("Hello world!")
print("Hello world")
// Declaring values is done using either var or val
// val declarations are immutable, whereas var's are mutable. Immutability is
// val declarations are immutable, whereas var's are mutable. Immutability is
// a good thing.
val x = 10 // x is now 10
x = 20 // error: reassignment to val
var x = 10
var x = 10
x = 20 // x is now 20
// Single line comments start with two forward slashes
/*
/*
Multi line comments look like this.
*/
@ -82,262 +83,6 @@ true == false // false
*/
// Everything is an object, including a function. Type these in the REPL:
7 // results in res30: Int = 7 (res30 is just a generated var name for the result)
// The next line gives you a function that takes an Int and returns it squared
(x:Int) => x * x
// You can assign this function to an identifier, like this:
val sq = (x:Int) => x * x
/* The above says this
sq: Int => Int = <function1>
Which means that this time we gave an explicit name to the value - sq is a
function that take an Int and returns Int.
sq can be executed as follows:
*/
sq(10) // Gives you this: res33: Int = 100.
// The colon explicitly defines the type of a value, in this case a function
// taking an Int and returning an Int.
val add10: Int => Int = _ + 10
// Scala allows methods and functions to return, or take as parameters, other
// functions or methods.
List(1, 2, 3) map add10 // List(11, 12, 13) - add10 is applied to each element
// Anonymous functions can be used instead of named functions:
List(1, 2, 3) map (x => x + 10)
// And the underscore symbol, can be used if there is just one argument to the
// anonymous function. It gets bound as the variable
List(1, 2, 3) map (_ + 10)
// If the anonymous block AND the function you are applying both take one
// argument, you can even omit the underscore
List("Dom", "Bob", "Natalia") foreach println
// Data structures
val a = Array(1, 2, 3, 5, 8, 13)
a(0)
a(3)
a(21) // Throws an exception
val m = Map("fork" -> "tenedor", "spoon" -> "cuchara", "knife" -> "cuchillo")
m("fork")
m("spoon")
m("bottle") // Throws an exception
val safeM = m.withDefaultValue("no lo se")
safeM("bottle")
val s = Set(1, 3, 7)
s(0)
s(1)
/* Look up the documentation of map here -
* http://www.scala-lang.org/api/current/index.html#scala.collection.immutable.Map
* and make sure you can read it
*/
// Tuples
(1, 2)
(4, 3, 2)
(1, 2, "three")
(a, 2, "three")
// Why have this?
val divideInts = (x:Int, y:Int) => (x / y, x % y)
divideInts(10,3) // The function divideInts gives you the result and the remainder
// To access the elements of a tuple, use _._n where n is the 1-based index of
// the element
val d = divideInts(10,3)
d._1
d._2
// Combinators
s.map(sq)
val sSquared = s. map(sq)
sSquared.filter(_ < 10)
sSquared.reduce (_+_)
// The filter function takes a predicate (a function from A -> Boolean) and
// selects all elements which satisfy the predicate
List(1, 2, 3) filter (_ > 2) // List(3)
List(
Person(name = "Dom", age = 23),
Person(name = "Bob", age = 30)
).filter(_.age > 25) // List(Person("Bob", 30))
// Scala a foreach method defined on certain collections that takes a type
// returning Unit (a void method)
aListOfNumbers foreach (x => println(x))
aListOfNumbers foreach println
// For comprehensions
for { n <- s } yield sq(n)
val nSquared2 = for { n <- s } yield sq(n)
for { n <- nSquared2 if n < 10 } yield n
for { n <- s; nSquared = n * n if nSquared < 10} yield nSquared
/* NB Those were not for loops. The semantics of a for loop is 'repeat', whereas
a for-comprehension defines a relationship between two sets of data. */
// Loops and iteration
1 to 5
val r = 1 to 5
r.foreach( println )
r foreach println
// NB: Scala is quite lenient when it comes to dots and brackets - study the
// rules separately. This helps write DSLs and APIs that read like English
(5 to 1 by -1) foreach ( println )
// A while loops
var i = 0
while (i < 10) { println("i " + i); i+=1 }
while (i < 10) { println("i " + i); i+=1 } // Yes, again. What happened? Why?
i // Show the value of i. Note that while is a loop in the classical sense -
// it executes sequentially while changing the loop variable. while is very
// fast, faster that Java // loops, but using the combinators and
// comprehensions above is easier to understand and parallelize
// A do while loop
do {
println("x is still less than 10");
x += 1
} while (x < 10)
// Tail recursion is an idiomatic way of doing recurring things in Scala.
// Recursive functions need an explicit return type, the compiler can't infer it.
// Here it's Unit.
def showNumbersInRange(a:Int, b:Int):Unit = {
print(a)
if (a < b)
showNumbersInRange(a + 1, b)
}
// Conditionals
val x = 10
if (x == 1) println("yeah")
if (x == 10) println("yeah")
if (x == 11) println("yeah")
if (x == 11) println ("yeah") else println("nay")
println(if (x == 10) "yeah" else "nope")
val text = if (x == 10) "yeah" else "nope"
var i = 0
while (i < 10) { println("i " + i); i+=1 }
// Object oriented features
// Classname is Dog
class Dog {
//A method called bark, returning a String
def bark: String = {
// the body of the method
"Woof, woof!"
}
}
// Classes can contain nearly any other construct, including other classes,
// functions, methods, objects, case classes, traits etc.
// Case classes
case class Person(name:String, phoneNumber:String)
Person("George", "1234") == Person("Kate", "1236")
// Pattern matching
val me = Person("George", "1234")
me match { case Person(name, number) => {
"We matched someone : " + name + ", phone : " + number }}
me match { case Person(name, number) => "Match : " + name; case _ => "Hm..." }
me match { case Person("George", number) => "Match"; case _ => "Hm..." }
me match { case Person("Kate", number) => "Match"; case _ => "Hm..." }
me match { case Person("Kate", _) => "Girl"; case Person("George", _) => "Boy" }
val kate = Person("Kate", "1234")
kate match { case Person("Kate", _) => "Girl"; case Person("George", _) => "Boy" }
// Regular expressions
val email = "(.*)@(.*)".r // Invoking r on String makes it a Regex
val serialKey = """(\d{5})-(\d{5})-(\d{5})-(\d{5})""".r // Using verbatim (multiline) syntax
val matcher = (value: String) => {
println(value match {
case email(name, domain) => s"It was an email: $name"
case serialKey(p1, p2, p3, p4) => s"Serial key: $p1, $p2, $p3, $p4"
case _ => s"No match on '$value'" // default if no match found
})
}
matcher("mrbean@pyahoo.com") // => "It was an email: mrbean"
matcher("nope..") // => "No match on 'nope..'"
matcher("52917") // => "No match on '52917'"
matcher("52752-16432-22178-47917") // => "Serial key: 52752, 16432, 22178, 47917"
// Strings
"Scala strings are surrounded by double quotes" //
@ -379,8 +124,291 @@ val html = """<form id="daform">
</form>"""
#################################################
## 2. Functions
#################################################
// Application structure and organization
// The next line gives you a function that takes an Int and returns it squared
(x:Int) => x * x
// You can assign this function to an identifier, like this:
val sq = (x:Int) => x * x
/* The above says this
sq: Int => Int = <function1>
Which means that this time we gave an explicit name to the value - sq is a
function that take an Int and returns Int.
sq can be executed as follows:
*/
sq(10) // Gives you this: res33: Int = 100.
// The colon explicitly defines the type of a value, in this case a function
// taking an Int and returning an Int.
val add10: Int => Int = _ + 10
#################################################
## 3. Flow Control
#################################################
1 to 5
val r = 1 to 5
r.foreach( println )
r foreach println
// NB: Scala is quite lenient when it comes to dots and brackets - study the
// rules separately. This helps write DSLs and APIs that read like English
(5 to 1 by -1) foreach ( println )
// A while loops
var i = 0
while (i < 10) { println("i " + i); i+=1 }
while (i < 10) { println("i " + i); i+=1 } // Yes, again. What happened? Why?
i // Show the value of i. Note that while is a loop in the classical sense -
// it executes sequentially while changing the loop variable. while is very
// fast, faster that Java // loops, but using the combinators and
// comprehensions above is easier to understand and parallelize
// A do while loop
do {
println("x is still less than 10");
x += 1
} while (x < 10)
// Tail recursion is an idiomatic way of doing recurring things in Scala.
// Recursive functions need an explicit return type, the compiler can't infer it.
// Here it's Unit.
def showNumbersInRange(a:Int, b:Int):Unit = {
print(a)
if (a < b)
showNumbersInRange(a + 1, b)
}
// Conditionals
val x = 10
if (x == 1) println("yeah")
if (x == 10) println("yeah")
if (x == 11) println("yeah")
if (x == 11) println ("yeah") else println("nay")
println(if (x == 10) "yeah" else "nope")
val text = if (x == 10) "yeah" else "nope"
var i = 0
while (i < 10) { println("i " + i); i+=1 }
#################################################
## 4. Data Structures
#################################################
val a = Array(1, 2, 3, 5, 8, 13)
a(0)
a(3)
a(21) // Throws an exception
val m = Map("fork" -> "tenedor", "spoon" -> "cuchara", "knife" -> "cuchillo")
m("fork")
m("spoon")
m("bottle") // Throws an exception
val safeM = m.withDefaultValue("no lo se")
safeM("bottle")
val s = Set(1, 3, 7)
s(0)
s(1)
/* Look up the documentation of map here -
* http://www.scala-lang.org/api/current/index.html#scala.collection.immutable.Map
* and make sure you can read it
*/
// Tuples
(1, 2)
(4, 3, 2)
(1, 2, "three")
(a, 2, "three")
// Why have this?
val divideInts = (x:Int, y:Int) => (x / y, x % y)
divideInts(10,3) // The function divideInts gives you the result and the remainder
// To access the elements of a tuple, use _._n where n is the 1-based index of
// the element
val d = divideInts(10,3)
d._1
d._2
#################################################
## 5. Object Oriented Programming
#################################################
/*
Aside: Everything we've done so far in this tutorial has been simple
expressions (values, functions, etc). These expressions are fine to type into
the command-line interpreter for quick tests, but they cannot exist by
themselves in a Scala file. For example, you cannot have just "val x = 5" in
a Scala file. Instead, the only top-level constructs allowed in Scala are:
- objects
- classes
- case classes
- traits
And now we will explain what these are.
*/
class Dog {
//A method called bark, returning a String
def bark: String = {
// the body of the method
"Woof, woof!"
}
}
// Classes can contain nearly any other construct, including other classes,
// functions, methods, objects, case classes, traits etc.
// Case classes
case class Person(name:String, phoneNumber:String)
Person("George", "1234") == Person("Kate", "1236")
// Objects and traits coming soon!
#################################################
## 6. Pattern Matching
#################################################
val me = Person("George", "1234")
me match { case Person(name, number) => {
"We matched someone : " + name + ", phone : " + number }}
me match { case Person(name, number) => "Match : " + name; case _ => "Hm..." }
me match { case Person("George", number) => "Match"; case _ => "Hm..." }
me match { case Person("Kate", number) => "Match"; case _ => "Hm..." }
me match { case Person("Kate", _) => "Girl"; case Person("George", _) => "Boy" }
val kate = Person("Kate", "1234")
kate match { case Person("Kate", _) => "Girl"; case Person("George", _) => "Boy" }
// Regular expressions
val email = "(.*)@(.*)".r // Invoking r on String makes it a Regex
val serialKey = """(\d{5})-(\d{5})-(\d{5})-(\d{5})""".r // Using verbatim (multiline) syntax
val matcher = (value: String) => {
println(value match {
case email(name, domain) => s"It was an email: $name"
case serialKey(p1, p2, p3, p4) => s"Serial key: $p1, $p2, $p3, $p4"
case _ => s"No match on '$value'" // default if no match found
})
}
matcher("mrbean@pyahoo.com") // => "It was an email: mrbean"
matcher("nope..") // => "No match on 'nope..'"
matcher("52917") // => "No match on '52917'"
matcher("52752-16432-22178-47917") // => "Serial key: 52752, 16432, 22178, 47917"
#################################################
## 7. Functional Programming
#################################################
// Scala allows methods and functions to return, or take as parameters, other
// functions or methods.
List(1, 2, 3) map add10 // List(11, 12, 13) - add10 is applied to each element
// Anonymous functions can be used instead of named functions:
List(1, 2, 3) map (x => x + 10)
// And the underscore symbol, can be used if there is just one argument to the
// anonymous function. It gets bound as the variable
List(1, 2, 3) map (_ + 10)
// If the anonymous block AND the function you are applying both take one
// argument, you can even omit the underscore
List("Dom", "Bob", "Natalia") foreach println
// Combinators
s.map(sq)
val sSquared = s. map(sq)
sSquared.filter(_ < 10)
sSquared.reduce (_+_)
// The filter function takes a predicate (a function from A -> Boolean) and
// selects all elements which satisfy the predicate
List(1, 2, 3) filter (_ > 2) // List(3)
List(
Person(name = "Dom", age = 23),
Person(name = "Bob", age = 30)
).filter(_.age > 25) // List(Person("Bob", 30))
// Scala a foreach method defined on certain collections that takes a type
// returning Unit (a void method)
aListOfNumbers foreach (x => println(x))
aListOfNumbers foreach println
// For comprehensions
for { n <- s } yield sq(n)
val nSquared2 = for { n <- s } yield sq(n)
for { n <- nSquared2 if n < 10 } yield n
for { n <- s; nSquared = n * n if nSquared < 10} yield nSquared
/* NB Those were not for loops. The semantics of a for loop is 'repeat', whereas
a for-comprehension defines a relationship between two sets of data. */
#################################################
## 8. Implicits
#################################################
Coming soon!
#################################################
## 9. Misc
#################################################
// Importing things
import scala.collection.immutable.List