Clojure was first FP, but because of the JVM, there was a need to make some compromises, including some OO programming methods
Scala first is OO, Java syntax is too redundant, a more mediocre language, Scala first do is to simplify, in a more concise way to write Oo, the main use of ' type inference ' can be inferred, you do not have to write, but if only this, it is better to use Python
So Scala, like its name, "Extensible Language", is a big bazaar that actively absorbs the excellent features of other languages, most importantly FP, you can use Scala to write Oo, but it recommends using FP to write Scala; Also includes the Actor model in Erlang
So Scala is not easy to learn, because it's more complicated.
0Scala Interpreter
Scala> 1 + 2res0:int = 3scala> Res0 * 3res1:int = 9scala> println ("Hello, world!") Hello, world!.
Code paragraph
In Scala, often omitted, but if there are multiple statements on one line, you must add
val s = "Hello"; println (s)
If a statement is to be written in multiple lines
X
+ y
This will be treated as 2 statements, two methods resolved,
(x
+ y)//brackets
X +
Y +
z//Put the operator in the previous line, implying that this sentence is not finished
1 Basic Syntax Basic types
Rich wrappers, providing more operations for basic types
Variable definition
val, immutable variable, constant, suitable for FP
var, variable variable, suitable for OO
scala> val msg = "Hello, world!" msg:java.lang.String = Hello, world!scala> msg = "Goodbye cruel world!" <console>:5:error:reassignment to Val msg = "Goodbye cruel world!"
function definition
can be abbreviated to, the return value type does not need to write, you can infer that there is only one statement, so {} can be omitted
else YMAX2: (int,int) Int
Simple Funciton, the return value is unit, similar to void (the difference is void is no return value, and Scala has a return value, just returned as Unit, ())
Scala> def greet () = println ("Hello, world!") Greet: () Unit
Scala> greet () = = ()
Boolean = True
function parameter is not variable
def add (b:byte): Unit = {
b = 1//This won ' t compile, because B is a Val
sum + = b
}
Repeating parameters, the last * represents a mutable argument list, can pass in multiple string
for (Arg <-args) println (ARG)
scala> echo ("Hello", "world!")
Hello
world!
Function literal
How to translate ...
The basis of the Scala FP, function as first class, is passed as a parameter in the form of function literal
Args.foreach ((arg:string) = println (ARG))
Args.foreach (arg = println (ARG))//omitted type
Args.foreach (println)//actually even the list of entries can be omitted
You can see that Scala can say enough to omit the code, as long as you can infer that you do not write, which is a form of static type system to make up
For OO programmers, it may be more difficult to understand, in fact, equal to
for (Arg <args)
println (ARG)
Control structure
Because Scala is biased to FP, all control structures have return values, which makes it easy for FP to program
If, you can return a value
val filename = if (!args.isempty) args (0) Else "default.txt"
while, in the FP does not recommend the use of loops, should be recursive, as far as possible to avoid
for, no use or brevity of Python and Clojure
for (File <-fileshere //generator, for Traversal, Each file is newly initialized if file.isfile; //filter conditions, multiple rooms need to be used; if file.getName.endsWith (".scala"); //Second filter line <-filelines (file) //nesting for trimmed = Line.trim //mid-stream variable bindings, Val type, similar to Clojure let if trimmed.matches (pattern)) println (file + ":" + trimmed)
For default does not produce a new collection, you must use yielddef Scalafiles = for { file <fileshere if File.getName.endsWith (" . Scala ") //yield produces a new collection, similar to Python
match, switch-case
Can return values, FP style, so that only one last println is required
Default will break, do not need to add each time
Else "val friend = Firstarg Match {case "Salt "+" case "chips" + "case"eg GS "=" case_ = "//default}println (Friend)
2 array of data structures
Variable sequence of homogeneous objects, suitable for OO scenarios
Val greetstrings = new Array[string] (3)//greetstrings is Val, but the inner array value is variable
Greetstrings (0) = "Hello" //scala with () rather than []
Greetstrings (1) = ","
Greetstrings (2) = "world!\n"
for (i <-0 to 2)
Print (Greetstrings (i))
Scala operators are equivalent to methods, so any method can be used in the form of an operator
1 + 2//(1). + (2), in the case of only one parameter, can be omitted. and ()
0 to 2//(0) to (2)
Greetstrings (0)//greetstrings.apply (0), which is why Scala uses () rather than []
Greetstrings (0) = "Hello"//greetstrings.update (0, "Hello")
Simplified array Initialization
Val numnames = Array ("zero", "one", "one") //array.apply ("zero", "one", "one")
List
List is an immutable sequence of objects relative to array, suitable for FP scenes
Val onetwo = List (1, 2)
Val threefour = List (3, 4)
Val zeroonetwo = 0:: Onetwo//::
Val onetwothreefour = onetwo::: Threefour
The most common operators for list are::, cons, put the new elem on the list front
:::, merge of two lists
Right operand,::
In general, the left operand, for example, a * b = a.* (b)
But when the method name is: End, the right operand
1:: Twothree = twothree.::(1)
Append not supported
The reason is that the time of this operation will grow linearly with the length of the list, so it is not supported, only support the front-end cons, it is necessary append can consider Listbuffer
Tuple
The tuple and list are immutable, except that the Elem in the list must be of the same type, but the tuple can contain different types of elem
Val pair = ("//Auto inferred type is, Tuple2[int, String]println (pair._1) //elem access method differs from list, due to different elem types in tuples
Set and map
var jetSet = Set ("Boeing", "Airbus")
JetSet + = "Lear"
println (Jetset.contains ("Cessna"))
Val treasuremap = Map[int, String] () Treasuremap + = (1--"Go to Island") Treasuremap + = (2, "Find big X on ground.") println (Treasuremap (2))
Val romannumeral = Map (1, "I", 2--"II", 3--"III")//shorthand
Scala requires both OO and FP, so mutable and immutable versions are required
Here the default is immutable, if you need to use the mutable version, you need to display the reference before use ...
Import Scala.collection.mutable.Set
Import Scala.collection.mutable.Map
3 Object-oriented-oo classes and objects
Relatively simple compared to Java definitions, default public
Class Checksumaccumulator {
private var sum = 0
def add (b:byte): Unit = {
sum + = b
} def checksum (): Int = {
return ~ (Sum & 0xFF) + 1
}
}
Further simplification, removing {} and return, defaults to returning the last computed value
Do not write return is the recommended way because the function tries not to have multiple exits
Class Checksumaccumulator {
private var sum = 0
def add (b:byte): Unit = sum + = b
def checksum (): Int = ~ (Sum & 0xFF) + 1
}
In fact, for the Unit (void), that is, there is no return value, for the FP, that function will only produce side effect, there is another shorthand way
Class Checksumaccumulator {
private var sum = 0
def add (b:byte) {sum + = b}//For the unit returned, another shorthand, with {} to indicate no return, so the front is not to write
def checksum (): Int = ~ (Sum & 0xFF) + 1
}
Instantiation of
Val acc = new Checksumaccumulator
Val CSA = new Checksumaccumulator
Acc.sum = 3
Singleton object
Scala cannot define static members, so use singleton objects to achieve the same goal
Import Scala.collection.mutable.Mapobject Checksumaccumulator { //Use object instead of class private Val cache = map[string, int] () def calculate (s:string): int = if (Cache.contains (s)) cache (s) for (c <s) Acc.add (c.tobyte) Val cs = acc.checksum () cache + = (S-CS) cs}}
The most common scenario is that, as the entrance to the Scala program,
To run a Scala program, you must supply the name of a standalone singleton object with a Main method tha T takes one parameter (array[string]), and has a result type of Unit.
Import checksumaccumulator.calculate object Summer { def main (args:array[string]) {for (Arg < args) println (arg + ":" + Calculate (ARG)) }}
Immutable objects
Applies to the FP scene object, so it is also called functional Objects.
Benefits, eliminate the complexity of the variable, can be assured when the parameters passed, multi-threaded use AH ...
The following is an example of defining a rational number class
Class Rational (N:int, D:int) //Minimalist mode, no classes body
As defined above, there is no need to define member variables, but only through parameters, because there is no member variable defined, so there is nowhere to be mutable.
Class Rational (N:int, D:int) {require (d! = 0)Precondition, if require returns false will throw illegalargumentexception, block initializationPrivate Val g = gcd (N.abs, d.abs) val numer = n/g//Add immutable Member field for easy reference val denom = d/g def this (n:int) = This ( N, 1) //Auxiliary constructor Def + (that:rational): Rati Onal = //define operator new Rational (Numer * that.denom + that.numer * denom, Denom * that.denom //can also use This.number reference to ) def + (i:int): Rational = //Typical member function overloading new Rational (Numer + i * denom, denom) override def toString = Numer + " /"+ denom //override, method overload Private Def gcd (A:int, b:int): Int = if (b = = 0) A else gcd (b, a% b) }
4 function programming-FP functions and closures
member functions , OO Way
internal functions that require sharding and do not want to contaminate external namespaces
first-class function, unnamed function literal
Function-like variables can be assigned and passed as arguments, but in Scala it needs to be in the form of functions literal, which is instantiated at run time as a value
scala> var increase = (X:int) + x + 1scala> Increase (10)
Partially applied functions
scala> def sum (a:int, b:int, c:int) = a + B + cscala> val A = Sum _ //Replace the entire parameter list with placeholders scala> a (1, 2, 3)
//partial function, substituting a placeholder for a parameter scala> B (2) Res15:int = 6
Closures
On the explanation of closures,
For the usual function, (x:int) + = x + 1, called closed term
and for (X:int) = x + more, called open term
So for the open, it must be at the time of the definition of the free variable more dynamic binding, so the context must have a definition of more, the closure of the open term process produced closure
scala> var more = 1scala> val Addmore = (x:int) + x + more //generated closures, binding morescala> Addmore (Res19:int) = 11scala> more = 9999 scala> Addmore (Ten) Res21:int = 10009 //visible closure binding is not value, but the variable itself
Just see some surprised, go to clojure inside try, also such, bind the variable itself, the closure will take the latest value
Of course, the use of closures is generally not the case.
The following example is a more common case where the parameters of the function are closed
How can I access a variable that does not already exist when the closure is called? When a closure is generated, the compiler puts the variable from the stack into the heap, so the function ends up with access to the
def makeincreaser (more:int) = (X:int) + x + more
scala> val inc1 = makeincreaser (1)
scala> val inc9999 = makeincreaser (9999)
Scala> INC1 (10)
Res24:int = 11
Scala> inc9999 (10)
Res25:int = 10009
Currying
Increase the comparison of the two versions of Sum first,
Scala> def plainoldsum (x:int, y:int) = x + yscala> plainoldsum (1, 2) Res4:int = 3scala> def curriedsum (X:int) ( Y:int) = x + y //currying version of sumcurriedsum: (int) (int) intscala> curriedsum (1) (2) Res5:int = 3
In fact currying, equivalent to calling two functions, first returns the function value of the second function, where closure x
Scala> def first (x:int) = (Y:int) + x + yfirst: (int) (int) + int
Remove the function value, the effect is to reduce the number of parameters, the first function of the parameters have been closure in the second function, and partially somewhat similar (difference)
scala> val onePlus = curriedsum (1) _oneplus: (int) + int = <function>scala> OnePlus (2) Res7:int = 3
What's the use? Used to create a control structure that is more like built-in
As below, {} is more like built-in, but {} has a restriction that only a single parameter list of arguments can be replaced with {}, so this time you need to use currying to reduce the number of entries
Scala> println ("Hello, world!") //Like method call Scala> println {"Hello, world!"} //More like the control structure of the built-in, such as if
For FP, use inheritance and polymorphism with respect to OO, use functions as parameters to implement code reuse, and hopefully you can put function values in {} and appear more like built-in
For example, the following, each open file, operation, close files, fixed mode, so implementation of Withprintwriter, each time a different OP can be different operations, regardless of the file switch
In the case of OO implementations, it is necessary to pass in the base class object and use the polymorphic implementation to make the function more lightweight
def withprintwriter (file:file, op:printwriter = Unit) { new PrintWriter (file) try { op (writer finally { writer.close ()} }//To use Withprintwriter ( "date.txt") in the way that the method is called ), writer = writer.println (new java.util.Date))
The parameters are reduced by currying, so you can use the {}
The new File ("date.txt") withprintwriter (file) {writer = writer.println (//) puts the value of the function in {}, much like built-in
Tail recursion, Tail recursion
As I said earlier, the FP avoids using loops and should use recursion
But the recursive efficiency is problematic, the stack is constantly stacked and it's easy to explode
So for some sort of recursion, tail recursion, the compiler automatically optimizes the loop execution to avoid using the stack multiple times.
The limitation is that not all situations can be written as tail recursion, in fact, only the loop can ...
Better than Clojuer, the compiler will automatically optimize
While, circular version, Oodef Approximateloop (initialguess:double): Double = { var guess = initialguess while (! Isgoodenough (guess)) guess improve (guess) guess}//recursive version, Fpdef approximate (guess:double): Double = if (Isgoodenough (guess)) Guess else approximate (improve (guess))
Scala Common syntax