您的位置:首页 > 其它

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.)

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.rule
The 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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: