Seven languages in seven weeks (notes on Scala)
2013-09-10 20:01
316 查看
Scala
unifying functional and object-oriented programming
A functional language has these characteristics:
• Functional programs are made up of functions.
• A function always returns a value.
• A function, given the same inputs, will return the same values.
• Functional programs avoid changing state or mutating data. Once you’ve set a value, you have to leave it alone.
Strictly speaking, Scala is not a pure functional programming language, just like C++ is not a pure object-oriented language.
Functional Programming and Concurrency
... Functional programming languages can solve these problems by eliminating mutable state from the equation. Scala does not force you to completely eliminate mutable state, but it does give you the tools to code things in a purely functional style.
(with some small exceptions) everything is an object in Scala: Integers and Strings are all objects. Scala is strongly typed (strong, static typing)
(Statically typed languages enforce polymorphism based on the structure of the types. Is it a duck by the genetic blueprint (static), or is it a duck because it quacks or walks like one? Statically typed languages benefit because compilers and tools know
more about your code to trap errors, highlight code, and refactor. The cost is having to do more work and living with some restrictions.)
no need to specify a type; Scala can infer the type, and bind types at compile time. ("val a:Int = 1" is fine, too)
"val" is immutable; "var" is not
"Nil" is an empty list. Neither "Nil" or "0" is a Boolean. (In Ruby, 0 evaluated to true; in C, 0 was false)
Loops:
Range:
Like Ruby, Scala supports first-class ranges
Tuple:
Class
Constructor:
When there’s something that can have only one instance, you’ll define it with the object keyword instead of the class keyword.
Inheritance:
Scala uses a concept called companion objects to mix class and instance methods on the same class. Where Ruby uses mixins and Java uses interfaces, Scala uses a structure like a mixin called a Trait .
Trait:
Above is about OO, below is about Functional Programming.
Function declarations:
Mutable state is bad. When you declare variables, you should make them immutable whenever you can to avoid conflicting state. In Java, that means using the final keyword. In Scala, immutable means using val instead of var:
It’s best to avoid var when you can for better concurrency. This basic design philosophy is the key element that differentiates functional programming from object-oriented programming: mutable state limits concurrency.
Scala’s primary collections are lists, sets, and maps.
List access is a function, so you use () instead of [] . Scala’s index for list starts with 0, as it does with Java and Ruby.
Nil in Scala is an empty list:
(omit Set, Map ...)
Foldleft:
/: is an operator with initialValue /: codeBlock
The syntax of the other version of foldLeft will seem strange to you. It uses a concept called currying. Functional languages use currying to transform a function with multiple parameters to several functions with their own parameter lists. Just understand
that what’s going on under the covers is a composition of functions rather than a single function.
XML as a first-class programming construct:
Pattern Matching and Guards:
Scala has first-class regular expressions. The .r method on a string can translate any string to a regular expression.
XML with matching:
Concurrency
The primary constructs are actors and message passing. Actors have pools of threads and queues. When you send a message to an actor (using the ! operator), you place an object on its queue. The actor reads the message and takes action. Often, the actor uses
a pattern matcher to detect the message and perform the appropriate message.
import scala.actors._
import scala.actors.Actor._
case object Poke
case object Feed
class Kid() extends Actor {
def act() {
loop {
react {
case Poke => {
println("Ow...")
println("Quit it...")
}
case Feed => {
println("Gurgle...")
println("Burp...")
}
}
}
}
}
val bart = new Kid().start
val lisa = new Kid().start
println("Ready to poke and feed...")
bart ! Poke
lisa ! Poke
bart ! Feed
lisa ! Feed
to do things asynchronously:
import scala.io._
import scala.actors._
import Actor._
// START:loader
object PageLoader {
def getPageSize(url : String) = Source.fromURL(url).mkString.length
}
// END:loader
val urls = List("http://www.amazon.com/",
"http://www.twitter.com/",
"http://www.google.com/",
"http://www.cnn.com/" )
// START:time
def timeMethod(method: () => Unit) = {
val start = System.nanoTime
method()
val end = System.nanoTime
println("Method took " + (end - start)/1000000000.0 + " seconds.")
}
// END:time
// START:sequential
def getPageSizeSequentially() = {
for(url <- urls) {
println("Size for " + url + ": " + PageLoader.getPageSize(url))
}
}
// END:sequential
// START:concurrent
def getPageSizeConcurrently() = {
val caller = self
for(url <- urls) {
actor { caller ! (url, PageLoader.getPageSize(url)) }
}
for(i <- 1 to urls.size) {
receive {
case (url, size) =>
println("Size for " + url + ": " + size)
}
}
}
// END:concurrent
// START:script
println("Sequential run:")
timeMethod { getPageSizeSequentially }
println("Concurrent run")
timeMethod { getPageSizeConcurrently }
// END:script
The "receive" method is where the real work happens.
Core strengths:
1. Concurrency
2. Evolution of legacy Java
3. Domain-specific languages
4. XML
5. Bridging (functional programming and OO)
Weaknesses:
1. Static typing
2. Syntax
3. Mutability
unifying functional and object-oriented programming
A functional language has these characteristics:
• Functional programs are made up of functions.
• A function always returns a value.
• A function, given the same inputs, will return the same values.
• Functional programs avoid changing state or mutating data. Once you’ve set a value, you have to leave it alone.
Strictly speaking, Scala is not a pure functional programming language, just like C++ is not a pure object-oriented language.
Functional Programming and Concurrency
... Functional programming languages can solve these problems by eliminating mutable state from the equation. Scala does not force you to completely eliminate mutable state, but it does give you the tools to code things in a purely functional style.
(with some small exceptions) everything is an object in Scala: Integers and Strings are all objects. Scala is strongly typed (strong, static typing)
(Statically typed languages enforce polymorphism based on the structure of the types. Is it a duck by the genetic blueprint (static), or is it a duck because it quacks or walks like one? Statically typed languages benefit because compilers and tools know
more about your code to trap errors, highlight code, and refactor. The cost is having to do more work and living with some restrictions.)
scala> val a = 1 a: Int = 1 scala> val b = 2 b: Int = 2 scala> if ( b < a) { | println("true") | } else { | println("false") | } false
no need to specify a type; Scala can infer the type, and bind types at compile time. ("val a:Int = 1" is fine, too)
"val" is immutable; "var" is not
"Nil" is an empty list. Neither "Nil" or "0" is a Boolean. (In Ruby, 0 evaluated to true; in C, 0 was false)
Loops:
def whileLoop { var i = 1 while(i <= 3) { println(i) i += 1 } } whileLoop
def forLoop { println( "for loop using Java-style iteration" ) for(i <- 0 until args.length) { println(args(i)) } } forLoop
def rubyStyleForLoop { println( "for loop using Ruby-style iteration" ) args.foreach { arg => println(arg) } } rubyStyleForLoop
Range:
Like Ruby, Scala supports first-class ranges
scala> val range = 0 until 10 range: Range = Range(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) scala> range.start res2: Int = 0 scala> range.end res3: Int = 10 scala> range.step res4: Int = 1 scala> (0 to 10) by 5 res6: Range = Range(0, 5, 10) scala> (0 to 10) by 6 res7: Range = Range(0, 6) scala> (0 until 10 by 5) res0: Range = Range(0, 5) scala> val range = (10 until 0) by -1 range: Range = Range(10, 9, 8, 7, 6, 5, 4, 3, 2, 1) scala> val range = 'a' to 'e' range: RandomAccessSeq.Projection[Char] = RandomAccessSeq.Projection(a, b, c, d, e)
Tuple:
scala> val person = ("Elvis", "Presley") person: (java.lang.String, java.lang.String) = (Elvis,Presley) scala> person._1 res9: java.lang.String = Elvis scala> val (x, y) = (1, 2) x: Int = 1 y: Int = 2
Class
scala> class Person(firstName: String, lastName: String) defined class Person scala> val gump = new Person("Forrest", "Gump") gump: Person = Person@7c6d75b6
Constructor:
class Person(firstName: String) { println("Outer constructor") def this(firstName: String, lastName: String) { this(firstName) println("Inner constructor") } def talk() = println("Hi") } val bob = new Person("Bob") val bobTate = new Person("Bob", "Tate")
batate$ scala code/scala/constructor.scala Outer constructor Outer constructor Inner constructor
When there’s something that can have only one instance, you’ll define it with the object keyword instead of the class keyword.
object TrueRing { def rule = println("To rule them all") } TrueRing.ruleThe TrueRing definition works exactly like any class definition, but it creates a singleton object.
Inheritance:
class Person(val name: String) { def talk(message: String) = println(name + " says " + message) def id(): String = name } class Employee(override val name: String, val number: Int) extends Person(name) { override def talk(message: String) { println(name + " with number " + number + " says " + message) } override def id():String = number.toString } val employee = new Employee("Yoda", 4) employee.talk("Extend or extend not. There is no try.")
Scala uses a concept called companion objects to mix class and instance methods on the same class. Where Ruby uses mixins and Java uses interfaces, Scala uses a structure like a mixin called a Trait .
Trait:
class Person(val name:String) trait Nice { def greet() = println("Howdily doodily.") } class Character(override val name:String) extends Person(name) with Nice val flanders = new Character("Ned") flanders.greet
Above is about OO, below is about Functional Programming.
Function declarations:
scala> def double(x:Int):Int = x * 2 double: (Int)Int scala> double(4) res0: Int = 8 scala> def double(x:Int):Int = { | x * 2 | } double: (Int)Int scala> double(6) res3: Int = 12
Mutable state is bad. When you declare variables, you should make them immutable whenever you can to avoid conflicting state. In Java, that means using the final keyword. In Scala, immutable means using val instead of var:
scala> var mutable = "I am mutable" mutable: java.lang.String = I am mutable scala> mutable = "Touch me, change me..." mutable: java.lang.String = Touch me, change me... scala> val immutable = "I am not mutable" immutable: java.lang.String = I am not mutable scala> immutable = "Can't touch this" <console>:5: error: reassignment to val immutable = "Can't touch this" ^
It’s best to avoid var when you can for better concurrency. This basic design philosophy is the key element that differentiates functional programming from object-oriented programming: mutable state limits concurrency.
Scala’s primary collections are lists, sets, and maps.
scala> List(1, 2, 3) res4: List[Int] = List(1, 2, 3) scala> List("one", "two", 3) res6: List[Any] = List(one, two, 3) scala> List("one", "two", 3)(2) res7: Any = 3
List access is a function, so you use () instead of [] . Scala’s index for list starts with 0, as it does with Java and Ruby.
Nil in Scala is an empty list:
scala> Nil res33: Nil.type = List()
(omit Set, Map ...)
Foldleft:
scala> val list = List(1, 2, 3) list: List[Int] = List(1, 2, 3) scala> val sum = (0 /: list) {(sum, i) => sum + i} sum: Int = 6
/: is an operator with initialValue /: codeBlock
The syntax of the other version of foldLeft will seem strange to you. It uses a concept called currying. Functional languages use currying to transform a function with multiple parameters to several functions with their own parameter lists. Just understand
that what’s going on under the covers is a composition of functions rather than a single function.
scala> val list = List(1, 2, 3) list: List[Int] = List(1, 2, 3) scala> list.foldLeft(0)((sum, value) => sum + value) res54: Int = 6
XML as a first-class programming construct:
scala> val movies = | <movies> | <movie genre="action">Pirates of the Caribbean</movie> | <movie genre="fairytale">Edward Scissorhands</movie> | </movies> movies: scala.xml.Elem = <movies> <movie genre="action">Pirates of the Caribbean</movie> <movie genre="fairytale">Edward Scissorhands</movie> </movies> scala> movies.text res1: String = Pirates of the Caribbean Edward Scissorhands scala> val movieNodes = movies \ "movie" movieNodes: scala.xml.NodeSeq = <movie genre="action">Pirates of the Caribbean</movie> <movie genre="fairytale">Edward Scissorhands</movie> scala> movieNodes(0) res3: scala.xml.Node = <movie genre="action">Pirates of the Caribbean</movie> scala> movieNodes(0) \ "@genre" res4: scala.xml.NodeSeq = action
Pattern Matching and Guards:
def factorial(n: Int): Int = n match { case 0 => 1 case x if x > 0 => factorial(n - 1) * n } println(factorial(3)) println(factorial(0))
Scala has first-class regular expressions. The .r method on a string can translate any string to a regular expression.
scala> val reg = """^(F|f)\w * """.r reg: scala.util.matching.Regex = ^(F|f)\w * scala> println(reg.findFirstIn("Fantastic")) Some(Fantastic) scala> println(reg.findFirstIn("not Fantastic")) None
XML with matching:
val movies = <movies> <movie>The Incredibles</movie> <movie>WALL E</movie> <short>Jack Jack Attack</short> <short>Geri's Game</short> </movies> (movies \ "_").foreach { movie => movie match { case <movie>{movieName}</movie> => println(movieName) case <short>{shortName}</short> => println(shortName + " (short)") } }
Concurrency
The primary constructs are actors and message passing. Actors have pools of threads and queues. When you send a message to an actor (using the ! operator), you place an object on its queue. The actor reads the message and takes action. Often, the actor uses
a pattern matcher to detect the message and perform the appropriate message.
import scala.actors._
import scala.actors.Actor._
case object Poke
case object Feed
class Kid() extends Actor {
def act() {
loop {
react {
case Poke => {
println("Ow...")
println("Quit it...")
}
case Feed => {
println("Gurgle...")
println("Burp...")
}
}
}
}
}
val bart = new Kid().start
val lisa = new Kid().start
println("Ready to poke and feed...")
bart ! Poke
lisa ! Poke
bart ! Feed
lisa ! Feed
to do things asynchronously:
import scala.io._
import scala.actors._
import Actor._
// START:loader
object PageLoader {
def getPageSize(url : String) = Source.fromURL(url).mkString.length
}
// END:loader
val urls = List("http://www.amazon.com/",
"http://www.twitter.com/",
"http://www.google.com/",
"http://www.cnn.com/" )
// START:time
def timeMethod(method: () => Unit) = {
val start = System.nanoTime
method()
val end = System.nanoTime
println("Method took " + (end - start)/1000000000.0 + " seconds.")
}
// END:time
// START:sequential
def getPageSizeSequentially() = {
for(url <- urls) {
println("Size for " + url + ": " + PageLoader.getPageSize(url))
}
}
// END:sequential
// START:concurrent
def getPageSizeConcurrently() = {
val caller = self
for(url <- urls) {
actor { caller ! (url, PageLoader.getPageSize(url)) }
}
for(i <- 1 to urls.size) {
receive {
case (url, size) =>
println("Size for " + url + ": " + size)
}
}
}
// END:concurrent
// START:script
println("Sequential run:")
timeMethod { getPageSizeSequentially }
println("Concurrent run")
timeMethod { getPageSizeConcurrently }
// END:script
The "receive" method is where the real work happens.
Core strengths:
1. Concurrency
2. Evolution of legacy Java
3. Domain-specific languages
4. XML
5. Bridging (functional programming and OO)
Weaknesses:
1. Static typing
2. Syntax
3. Mutability
相关文章推荐
- Seven languages in seven weeks (notes on Haskell)
- Seven languages in seven weeks (notes on Prolog)
- Seven languages in seven weeks (notes on Ruby)
- Seven languages in seven weeks (notes on Erlang)
- Seven More Languages in Seven Weeks (读书笔记):Idris
- Seven Languages in Seven Weeks: A Pragmatic Guide to Learning Programming Languages/Bruce A. Tate-图书-卓越亚马逊
- Notes on reading: Functional Programming in Scala - Part 1
- Seven More Languages in Seven Weeks (读书笔记):Elm
- Seven More Languages in Seven Weeks (读书笔记):Julia
- Seven More Languages in Seven Weeks (读书笔记):Lua
- Seven More Languages in Seven Weeks (读书笔记):miniKaren
- Seven More Languages in Seven Weeks (读书笔记):Factor
- Seven Languages in Seven Weeks
- Seven Languages In Seven Weeks: Week 1 (Ruby) - Day 1
- Notes on Chinese Web Data Extraction in Java(part 3)
- Notes on the implementation of encryption in Android 3.0
- Robbie's Notes on File System Security in Linux (and comparison to Windows NT)
- Notes on Programming in C
- Scala 安装 Exception in thread "main" java.lang.VerifyError: Uninitialized object exists on backward branch 96
- Notes on the implementation of encryption in Android 3.0