Transform
List(1, 2, 3, 4, 5) map { _ * 2 }
Reduce
List(1, 2, 3, 4, 5) reduceLeft { _ * _ }
The first _ represents the argument that is accumulating the value of the reduction, and the second _ represents the current element of the list.
Function Literals and Closures
var factor = 3
val multiplier = (i:Int) => i * factor
val l1 = List(1, 2, 3, 4, 5) map multiplier
factor = 5
val l2 = List(1, 2, 3, 4, 5) map multiplier
println(l1)
println(l2)
We defined a variable, factor, to use as the multiplication factor, and we pulled out the previous anonymous function into a value called multiplier that now uses factor. Then we map over a list of integers, as we did before. After the first call to map, we change factor and map again. Here is the output:
List(3, 6, 9, 12, 15)
List(5, 10, 15, 20, 25)
Even though multiplier was an immutable function value, its behavior changed when factor changed.
Recursion
Recursion plays a larger role in pure functional programming than in imperative programming, in part because of the restriction that variables are immutable.
Tail Calls and Tail-Call Optimization
def factorial(i: BigInt): BigInt = {
def fact(i: BigInt, accumulator: BigInt): BigInt = i match {
case _ if i == 1 => accumulator
case _ => fact(i - 1, i * accumulator)
}
fact(i, 1)
}
for (i <- 1 to 10)
format("%s: %s\n", i, factorial(i))
Functional Data Structures
There are several data structures that are common in functional programming, most of which are containers, like collections.
Lists in Functional Programming
val list1 = List("Programming", "Scala")
val list2 = "People" :: "should" :: "read" :: list1
println(list2)
Because the :: operator binds to the right, the definition of list2 is equivalent to both of the following variations:
val list2 = ("People" :: ("should" :: ("read" :: list1)))
val list2 = list1.::("read").::("should").::("People")
Maps in Functional Programming
Sets in Functional Programming
Traversing, Mapping, Filtering, Folding, and Reducing
Traversal-foreach
List(1, 2, 3, 4, 5) foreach { i => println("Int: " + i) }
val stateCapitals = Map(
"Alabama" -> "Montgomery",
"Alaska" -> "Juneau",
"Wyoming" -> "Cheyenne")
stateCapitals foreach { kv => println(kv._1 + ": " + kv._2) }
The signature of foreach is the following:
trait Iterable[+A] {
...
def foreach(f : (A) => Unit) : Unit = ...
...
}
Mapping
val stateCapitals = Map(
"Alabama" -> "Montgomery",
"Alaska" -> "Juneau",
"Wyoming" -> "Cheyenne")
val lengths = stateCapitals map { kv => (kv._1, kv._2.length) }
println(lengths)
Filtering
val stateCapitals = Map(
"Alabama" -> "Montgomery",
"Alaska" -> "Juneau",
"Wyoming" -> "Cheyenne")
val map2 = stateCapitals filter { kv => kv._1 startsWith "A" }
println( map2 )
trait Iterable[+A] {
...
// Returns this iterable without its n first elements. If this iterable
// has less than n elements, the empty iterable is returned.
def drop (n : Int) : Collection[A] = ...
// Returns the longest suffix of this iterable whose first element does
// not satisfy the predicate p.
def dropWhile (p : (A) => Boolean) : Collection[A] = ...
// Apply a predicate p to all elements of this iterable object and
// return true, iff there is at least one element for which p yields true.
def exists (p : (A) => Boolean) : Boolean = ...
// Returns all the elements of this iterable that satisfy the predicate p.
// The order of the elements is preserved.
def filter (p : (A) => Boolean) : Iterable[A] = ...
// Find and return the first element of the iterable object satisfying a
// predicate, if any.
def find (p : (A) => Boolean) : Option[A] = ...
// Returns index of the first element satisying a predicate, or -1.
def findIndexOf (p : (A) => Boolean) : Int = ...
// Apply a predicate p to all elements of this iterable object and return
// true, iff the predicate yields true for all elements.
def forall (p : (A) => Boolean) : Boolean = ...
// Returns the index of the first occurence of the specified object in
// this iterable object.
def indexOf [B >: A](elem : B) : Int = ...
// Partitions this iterable in two iterables according to a predicate.
def partition (p : (A) => Boolean) : (Iterable[A], Iterable[A]) = ...
// Checks if the other iterable object contains the same elements.
def sameElements [B >: A](that : Iterable[B]) : Boolean = ...
// Returns an iterable consisting only over the first n elements of this
// iterable, or else the whole iterable, if it has less than n elements.
def take (n : Int) : Collection[A] = ...
}
// Returns the longest prefix of this iterable whose elements satisfy the
// predicate p.
def takeWhile (p : (A) => Boolean) : Iterable[A] = ...
Folding and Reducing
List(1,2,3,4,5,6) reduceLeft(_ + _)
21
List(1,2,3,4,5,6).foldLeft(10)(_ * _)
7200
List(1, 2, 3, 4, 5, 6).foldLeft(List[String]()) {
(list, x) => ("<" + x + ">") :: list
}.reverse
List(<1>, <2>, <3>, <4>, <5>, <6>)
trait Iterable[+A] {
...
// Combines the elements of this iterable object together using the
// binary function op, from left to right, and starting with the value z.
def foldLeft [B](z : B)(op : (B, A) => B) : B
// Combines the elements of this list together using the binary function
// op, from right to left, and starting with the value z.
def foldRight [B](z : B)(op : (A, B) => B) : B
// Similar to foldLeft but can be used as an operator with the order of
// list and zero arguments reversed. That is, z /: xs is the same as
// xs foldLeft z
def /: [B](z : B)(op : (B, A) => B) : B
// An alias for foldRight. That is, xs :\ z is the same as xs foldRight z
def :\ [B](z : B)(op : (A, B) => B) : B
// Combines the elements of this iterable object together using the
// binary operator op, from left to right
def reduceLeft [B >: A](op : (B, A) => B) : B
// Combines the elements of this iterable object together using the
// binary operator op, from right to left
def reduceRight [B >: A](op : (A, B) => B) : B
Functional Options
val someNumber = Some(5)
val noneNumber = None
for (option <- List(noneNumber, someNumber)) {
option.map(n => println(n * 5))
}
Pattern Matching
Pattern matching is a fundamental tool in functional programming. It’s just as important as polymorphism is in object-oriented programming, although the goals of the two techniques are very different.
Partial Functions
def concatUpper(s1: String, s2: String): String = (s1 + " " + s2).toUpperCase
val c = concatUpper _
println(c("short", "pants"))
val c2 = concatUpper("short", _: String)
println(c2("pants"))
val pantsTest: PartialFunction[String, String] = {
case "pants" => "yes, we have pants!"
}
println(pantsTest.isDefinedAt("pants"))
println(pantsTest.isDefinedAt("skort"))
Currying
scala> def cat(s1: String, s2: String) = s1 + s2
cat: (String,String)java.lang.String
scala> val curryCat = Function.curried(cat _)
curryCat: (String) => (String) => java.lang.String = <function>
scala> cat("foo", "bar") == curryCat("foo")("bar")
res2: Boolean = true
def multiplier(i: Int)(factor: Int) = i * factor
val byFive = multiplier(5) _
val byTen = multiplier(10) _
Implicit Conversions
import scala.runtime.RichString
class FancyString(val str: String)
object FancyString2RichString {
implicit def fancyString2RichString(fs: FancyString) =
new RichString(fs.str)
}
import FancyString2RichString._
val fs = new FancyString("scala")
println(fs.capitalize.reverse)
def multiplier(i: Int)(implicit factor: Int) {
println(i * factor)
}
implicit val factor = 2
multiplier(2)
multiplier(2)(3)
参考:《Programming Scala》
List(1, 2, 3, 4, 5) map { _ * 2 }
Reduce
List(1, 2, 3, 4, 5) reduceLeft { _ * _ }
The first _ represents the argument that is accumulating the value of the reduction, and the second _ represents the current element of the list.
Function Literals and Closures
var factor = 3
val multiplier = (i:Int) => i * factor
val l1 = List(1, 2, 3, 4, 5) map multiplier
factor = 5
val l2 = List(1, 2, 3, 4, 5) map multiplier
println(l1)
println(l2)
We defined a variable, factor, to use as the multiplication factor, and we pulled out the previous anonymous function into a value called multiplier that now uses factor. Then we map over a list of integers, as we did before. After the first call to map, we change factor and map again. Here is the output:
List(3, 6, 9, 12, 15)
List(5, 10, 15, 20, 25)
Even though multiplier was an immutable function value, its behavior changed when factor changed.
Recursion
Recursion plays a larger role in pure functional programming than in imperative programming, in part because of the restriction that variables are immutable.
Tail Calls and Tail-Call Optimization
def factorial(i: BigInt): BigInt = {
def fact(i: BigInt, accumulator: BigInt): BigInt = i match {
case _ if i == 1 => accumulator
case _ => fact(i - 1, i * accumulator)
}
fact(i, 1)
}
for (i <- 1 to 10)
format("%s: %s\n", i, factorial(i))
Functional Data Structures
There are several data structures that are common in functional programming, most of which are containers, like collections.
Lists in Functional Programming
val list1 = List("Programming", "Scala")
val list2 = "People" :: "should" :: "read" :: list1
println(list2)
Because the :: operator binds to the right, the definition of list2 is equivalent to both of the following variations:
val list2 = ("People" :: ("should" :: ("read" :: list1)))
val list2 = list1.::("read").::("should").::("People")
Maps in Functional Programming
Sets in Functional Programming
Traversing, Mapping, Filtering, Folding, and Reducing
Traversal-foreach
List(1, 2, 3, 4, 5) foreach { i => println("Int: " + i) }
val stateCapitals = Map(
"Alabama" -> "Montgomery",
"Alaska" -> "Juneau",
"Wyoming" -> "Cheyenne")
stateCapitals foreach { kv => println(kv._1 + ": " + kv._2) }
The signature of foreach is the following:
trait Iterable[+A] {
...
def foreach(f : (A) => Unit) : Unit = ...
...
}
Mapping
val stateCapitals = Map(
"Alabama" -> "Montgomery",
"Alaska" -> "Juneau",
"Wyoming" -> "Cheyenne")
val lengths = stateCapitals map { kv => (kv._1, kv._2.length) }
println(lengths)
Filtering
val stateCapitals = Map(
"Alabama" -> "Montgomery",
"Alaska" -> "Juneau",
"Wyoming" -> "Cheyenne")
val map2 = stateCapitals filter { kv => kv._1 startsWith "A" }
println( map2 )
trait Iterable[+A] {
...
// Returns this iterable without its n first elements. If this iterable
// has less than n elements, the empty iterable is returned.
def drop (n : Int) : Collection[A] = ...
// Returns the longest suffix of this iterable whose first element does
// not satisfy the predicate p.
def dropWhile (p : (A) => Boolean) : Collection[A] = ...
// Apply a predicate p to all elements of this iterable object and
// return true, iff there is at least one element for which p yields true.
def exists (p : (A) => Boolean) : Boolean = ...
// Returns all the elements of this iterable that satisfy the predicate p.
// The order of the elements is preserved.
def filter (p : (A) => Boolean) : Iterable[A] = ...
// Find and return the first element of the iterable object satisfying a
// predicate, if any.
def find (p : (A) => Boolean) : Option[A] = ...
// Returns index of the first element satisying a predicate, or -1.
def findIndexOf (p : (A) => Boolean) : Int = ...
// Apply a predicate p to all elements of this iterable object and return
// true, iff the predicate yields true for all elements.
def forall (p : (A) => Boolean) : Boolean = ...
// Returns the index of the first occurence of the specified object in
// this iterable object.
def indexOf [B >: A](elem : B) : Int = ...
// Partitions this iterable in two iterables according to a predicate.
def partition (p : (A) => Boolean) : (Iterable[A], Iterable[A]) = ...
// Checks if the other iterable object contains the same elements.
def sameElements [B >: A](that : Iterable[B]) : Boolean = ...
// Returns an iterable consisting only over the first n elements of this
// iterable, or else the whole iterable, if it has less than n elements.
def take (n : Int) : Collection[A] = ...
}
// Returns the longest prefix of this iterable whose elements satisfy the
// predicate p.
def takeWhile (p : (A) => Boolean) : Iterable[A] = ...
Folding and Reducing
List(1,2,3,4,5,6) reduceLeft(_ + _)
21
List(1,2,3,4,5,6).foldLeft(10)(_ * _)
7200
List(1, 2, 3, 4, 5, 6).foldLeft(List[String]()) {
(list, x) => ("<" + x + ">") :: list
}.reverse
List(<1>, <2>, <3>, <4>, <5>, <6>)
trait Iterable[+A] {
...
// Combines the elements of this iterable object together using the
// binary function op, from left to right, and starting with the value z.
def foldLeft [B](z : B)(op : (B, A) => B) : B
// Combines the elements of this list together using the binary function
// op, from right to left, and starting with the value z.
def foldRight [B](z : B)(op : (A, B) => B) : B
// Similar to foldLeft but can be used as an operator with the order of
// list and zero arguments reversed. That is, z /: xs is the same as
// xs foldLeft z
def /: [B](z : B)(op : (B, A) => B) : B
// An alias for foldRight. That is, xs :\ z is the same as xs foldRight z
def :\ [B](z : B)(op : (A, B) => B) : B
// Combines the elements of this iterable object together using the
// binary operator op, from left to right
def reduceLeft [B >: A](op : (B, A) => B) : B
// Combines the elements of this iterable object together using the
// binary operator op, from right to left
def reduceRight [B >: A](op : (A, B) => B) : B
Functional Options
val someNumber = Some(5)
val noneNumber = None
for (option <- List(noneNumber, someNumber)) {
option.map(n => println(n * 5))
}
Pattern Matching
Pattern matching is a fundamental tool in functional programming. It’s just as important as polymorphism is in object-oriented programming, although the goals of the two techniques are very different.
Partial Functions
def concatUpper(s1: String, s2: String): String = (s1 + " " + s2).toUpperCase
val c = concatUpper _
println(c("short", "pants"))
val c2 = concatUpper("short", _: String)
println(c2("pants"))
val pantsTest: PartialFunction[String, String] = {
case "pants" => "yes, we have pants!"
}
println(pantsTest.isDefinedAt("pants"))
println(pantsTest.isDefinedAt("skort"))
Currying
scala> def cat(s1: String, s2: String) = s1 + s2
cat: (String,String)java.lang.String
scala> val curryCat = Function.curried(cat _)
curryCat: (String) => (String) => java.lang.String = <function>
scala> cat("foo", "bar") == curryCat("foo")("bar")
res2: Boolean = true
def multiplier(i: Int)(factor: Int) = i * factor
val byFive = multiplier(5) _
val byTen = multiplier(10) _
Implicit Conversions
import scala.runtime.RichString
class FancyString(val str: String)
object FancyString2RichString {
implicit def fancyString2RichString(fs: FancyString) =
new RichString(fs.str)
}
import FancyString2RichString._
val fs = new FancyString("scala")
println(fs.capitalize.reverse)
def multiplier(i: Int)(implicit factor: Int) {
println(i * factor)
}
implicit val factor = 2
multiplier(2)
multiplier(2)(3)
参考:《Programming Scala》