What is currying? Let's assume we have function foo()
def foo = { ... }
libraryDependencies += ("org.scala-stm" %% "scala-stm" % "0.7")
Add dependency to pom.xml (for Scala 2.10)
<dependencies>
<dependency>
<groupId>org.scala-stm</groupId>
<artifactId>scala-stm_2.10</artifactId>
<version>0.7</version>
</dependency>
</dependencies>
import scala.concurrent.stm._Useful classes and methods
Ref, atomic, repeat
val userCount = Ref(42)Following attempt to call Ref.set() will not compile
userCount.get() //will not compileOutput
Exception:CompilerException: Compiler exception error: line 5: not enough arguments for method get: (implicit txn: scala.concurrent.stm.InTxn)Int. Unspecified value parameter txn. userCount.get() //will not compile ^
userCount.set() //will not compileOutput
Exception:CompilerException: Compiler exception error: line 5: not enough arguments for method set: (v: Int)(implicit txn: scala.concurrent.stm.InTxn)Unit. Unspecified value parameter v. userCount.set() //will not compile ^
val result = atomic { implicit tx => /*your code here*/ }
val x1 = atomic { userCount.get(_) } //() (result)
val x2 = atomic { implicit tx => userCount.get } //() (result)
userCount.single() //this will work //42 (result)and is equivalent to
atomic { userCount.get(_) } //42 (result)
atomic { implicit tx => userCount.set(56) } //() (result)
has shorter form
atomic { implicit tx => userCount() = 56 } //() (result)
Ref.get
atomic { implicit tx => val x = userCount.get; x } //42 (result)
has shorter form
atomic { implicit tx => val x = userCount(); x } //42 (result)
atomic { implicit tx => "Hello world!" }OutputHello world!
trait HasDebugString {
def toDebugString =
this.toString + " " + this.toString.length
}
class X extends HasDebugString
but it's impossible when we use third party code
class XDebug extends X with HasDebugStringBut we don't want to do this for each class in project, right?
case class X(text : String)
class DebugStringWrapper(instance : X) {
def toDebugString =
instance.toString + instance.toString.length
}
def wrap(instance : X) = new DebugStringWrapper(instance);
wrap(new X("ABC")).toDebugString
//X(ABC)6 (result)
//written only once
class DebugStringWrapper[T](instance : T) {
def toDebugString =
instance.toString + instance.toString.length
}
def wrap[T](instance : T) = new DebugStringWrapper(instance);
Other parts of code can use wrapper
case class X(text : String)
wrap(new X("ABC")).toDebugString //X(ABC)6 (result)
wrap(new X("ABC")).toDebugString //X(ABC)6 (result)
wrap(6).toDebugString //61 (result)
wrap("ABC").toDebugString //ABC3 (result)
wrap(List(1,2)).toDebugString //List(1, 2)10 (result)
wrap(6).toDebugString == 6.toDebugStringActually we can... implicit magic...
implicit def hiddenwrap[T](instance : T) = new DebugStringWrapper(instance);
wrap(List(1,2)).toDebugString //List(1, 2)10 (result)
hiddenwrap(List(1,2)).toDebugString //List(1, 2)10 (result)
List(1,2).toDebugString //List(1, 2)10 (result)
implicit def hiddenwrap[T](instance : T) = new {
def toDebugString = instance.toString + instance.toString.length
}
List(1,2,3).toDebugString //List(1, 2, 3)13 (result)
implicit def opwrap[T](instance : T) = new {
def ! = instance.toString + instance.toString.length
}
List(1,2,3).! //List(1, 2, 3)13 (result)The difference is that you can skip a dot
List(1,2,3)! //List(1, 2, 3)13 (result)
implicit def opwrap2[T](instance : List[T]) = new {
def unary_! = instance.isEmpty
}
println(!List(1,2,3)) //() false(result)
println(!Nil) //() true(result)
println(List(1,2,3).!) //() List(1, 2, 3)13(result)
implicit def opwrap3[TL](instance : List[TL]) = new {
def  =
if (instance.length > other.length) instance else other
}
List(1,2,3) ! List("A","B") //List(1, 2, 3) (result)
List(1,2,3).!(List("A","B")) //List(1, 2, 3) (result)
opwrap3(List(1,2,3)).!(List("A","B")) //List(1, 2, 3) (result)
implicit def opwrap4[TL](instance : List[TL]) = new {
def !:[TR](other : List[TR]) =
instance + ".!:(" + other + ")"
}
List(1,2,3) !: List("A","B") //List(A, B).!:(List(1, 2, 3)) (result)
List("A","B").!:(List(1,2,3)) //List(A, B).!:(List(1, 2, 3)) (result)
opwrap4(List("A","B")).!:(List(1,2,3)) //List(A, B).!:(List(1, 2, 3)) (result)
List(1,2,3).toDebugString
found : List[Int]
required: ?{def toDebugString: ?}
Note that implicit conversions are not applicable
because they are ambiguous:
both method hiddenwrap2 of type
[T](instance: T)AnyRef{def toDebugString: String}
and method hiddenwrap of type
[T](instance: T)DebugStringWrapper[T]
are possible conversion functions
from List[Int]to ?{def toDebugString: ?}
implicit def happystring[T](instance : T) = new {
override def toString = instance.toString + ":)"
def withSmiley = instance.toString + ":)"
}
//BAD: X has toString method
println(X("I'm sad").toString) //() X(I'm sad)(result)
//GOOD: toString is not found in X, so implicit conversion will be applied
println(X("I'm happy").withSmiley) //() X(I'm happy):)(result)
List[Double](1,2,3) //List(1.0, 2.0, 3.0) (result)
List[String]("A","B","C") //List(A, B, C) (result)
This information is not available at runtime.
Instead are types are replaced with "Any" typeval items1 = List(1,2,3) val items2 = items1.updated(1, "A")- there's no way to modify original collection (items1)
scala
Welcome to Scala version 2.10.3 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_25).
Type in expressions to have them evaluated.
Type :help for more information.
scala> println("Hello world")
Hello world
scala> exit
List(List(1),List(2),List(3)) .flatten //List(1, 2, 3) (result)Option is Traversable with 0 or 1 elements
Some("A").size //1 (result)
None.size //0 (result)
List(Some(1),Some(2),Some(3)) .flatten //List(1, 2, 3) (result)Flatten can be applied to any Traversable
List(Map(1->3),Map(1->8),Map(5->"A")) .flatten //List((1,3), (1,8), (5,A)) (result)flatten can be applied to Nil
Nil.flatten //List() (result)
val items = List(List("X"),List(2),List(3))
items //List(List(X), List(2), List(3)) (result)
typeOf(items) //List[List[Any]] (result)and function foo. Function must return a traversable
def foo(x : List[Any]) : List[String]= List("foo(" + x + ")")
apply map to each item
val mapitems = items.map(foo)
mapitemsOutput
List(List(foo(List(X))), List(foo(List(2))), List(foo(List(3))))
typeOf(mapitems) //List[List[String]] (result)apply flatten to the result of map
val flatmapitems = mapitems.flatten
flatmapitemsOutput
List(foo(List(X)), foo(List(2)), foo(List(3)))
typeOf(flatmapitems) //List[String] (result)
val flatmapitems2 = items.flatMap(foo)
flatmapitems2Output
List(foo(List(X)), foo(List(2)), foo(List(3)))
typeOf(flatmapitems2) //List[String] (result)
items //List(1, 2, 6, 4, 2, 1) (result)
def how1(currentItem : Int) = currentItem * 2and then apply it to each item
items.map(how1) //List(2, 4, 12, 8, 4, 2) (result)or
items.map(how1(_)) //List(2, 4, 12, 8, 4, 2) (result)We can replace
items.map(how1) //List(2, 4, 12, 8, 4, 2) (result)with
val result0 = how1(items(0)) // 2 val result1 = how1(items(1)) // 4 val result2 = how1(items(2)) // 12 // ... val resultn = how1(items(n)) // 2 val result = List(result0, ..., resultn) // List(2, 4, 12, 8, 4, 2)Since vars result0, result1, ... resultn are independent we can evaluate them in any order.
We must define how to do_something_with previous result and current item. We need binary operator or two argument function
val result0 = do_something_with(???, items(1)) val result1 = do_something_with(result0, items(1)) val result2 = do_something_with(result1, items(2)) // ... val resultn = do_something_with(resultn-1, items(n)) val result = List(result0, ..., resultn)
def how2(prevResult : Int, currentItem : Int)But for result0 there's no previous result, instead we provide some_input
= prevResult * currentItem + 1
val result0 = do_something_with(some_input, items(1))Replace do_something_with with how2.
val input = ??? val result0 = how2(input, items(1)) val result1 = how2(result0, items(1)) val result2 = how2(result1, items(2)) // ... val resultn = how2(resultn-1, items(n)) val result = List(input, result0, ..., resultn)Then we can shorten to form
items.scan(input)(how2)Time to provide input value
items.scan(0)(how2v)Code result
List(0, 1, 3, 19, 77, 155, 156)
how2(0, 1)=1 how2(1, 2)=3 how2(3, 6)=19 how2(19, 4)=77 how2(77, 2)=155 how2(155, 1)=156
input :: results
items //List(1, 2, 6, 4, 2, 1) (result)Sum of items
items.scan(0)(_+_)
0 1 3 9 13 15 16
items.scan(1)(_*_)
1 1 2 12 48 96 96
items.scan("input")("f(" + _ + ", " + _ + ")")
input f(input, 1) f(f(input, 1), 2) f(f(f(input, 1), 2), 6) f(f(f(f(input, 1), 2), 6), 4) f(f(f(f(f(input, 1), 2), 6), 4), 2) f(f(f(f(f(f(input, 1), 2), 6), 4), 2), 1)
List().scan(0)(_+_) //List(0) (result)single element list
List(0).scan(0)(_+_) //List(0, 0) (result)
items.scan(0)(how2)
0 1 3 19 77 155 156
items.scan(0)(how2).last //156 (result)or shorter form fold instead of scan
items.fold(0)(how2) //156 (result)
items //List(1, 2, 6, 4, 2, 1) (result)Sum of items
items.fold(0)(_+_) //16 (result)Product of items
items.fold(1)(_*_) //96 (result)As expression
items.fold("input")("f(" + _ + ", " + _ + ")")f(f(f(f(f(f(input, 1), 2), 6), 4), 2), 1)
List().fold(0)(_+_) //0 (result)single element list
List(0).fold(0)(_+_) //0 (result)
items //List(1, 2, 6, 4, 2, 1) (result)into head
items.head //1 (result)and tail
items.tail //List(2, 6, 4, 2, 1) (result)then use scan function
items.tail.scan(items.head)(how2) //List(1, 3, 19, 77, 155, 156) (result)if we need just last element...
items.tail.fold(items.head)(how2) //156 (result)Or use shorter form
items.reduce(how2) //156 (result)Examples List items
items //List(1, 2, 6, 4, 2, 1) (result)Sum of items
items.reduce(_+_) //16 (result)Product of items
items.reduce(_*_) //96 (result)As expression
items.map(_.toString).reduce("f(" + _ + ", " + _ + ")")f(f(f(f(f(1, 2), 6), 4), 2), 1)
List[Int]().reduce(_+_)
Exception:empty.reduceLeft
List[Int](0).reduce(_+_) //0 (result)
items.scan(0)(_+_) //List(0, 1, 3, 9, 13, 15, 16) (result)
items.scanLeft(0)(_+_) //List(0, 1, 3, 9, 13, 15, 16) (result)items.fold is eqivalent to items.foldLeft
items.fold(0)(_+_) //16 (result)
items.foldLeft(0)(_+_) //16 (result)items.reduce is eqivalent to items.reduceLeft
items.reduce(_+_) //16 (result)
items.reduceLeft(_+_) //16 (result)
items.scanRight(0)(_+_) //List(16, 15, 13, 7, 3, 1, 0) (result)Examples List items
items //List(1, 2, 6, 4, 2, 1) (result)Sum of items
items.scanRight(0)(_+_)
16 15 13 7 3 1 0
items.scanRight(1)(_*_)
96 96 48 8 2 1 1
items.scanRight("input")("f(" + _ + ", " + _ + ")")
f(1, f(2, f(6, f(4, f(2, f(1, input)))))) f(2, f(6, f(4, f(2, f(1, input))))) f(6, f(4, f(2, f(1, input)))) f(4, f(2, f(1, input))) f(2, f(1, input)) f(1, input) input
List[Int]().scanRight(0)(_+_) //List(0) (result)single element list
List(0).scanRight(0)(_+_) //List(0, 0) (result)
items.foldRight(0)(_+_) //16 (result)Examples List items
items //List(1, 2, 6, 4, 2, 1) (result)Sum of items
items.foldRight(0)(_+_) //16 (result)Product of items
items.foldRight(1)(_*_) //96 (result)As expression
items.foldRight("input")("f(" + _ + ", " + _ + ")")f(1, f(2, f(6, f(4, f(2, f(1, input))))))
List[Int]().foldRight(0)(_+_) //0 (result)single element list
List(0).foldRight(0)(_+_) //0 (result)
items.reduce(_+_) //16 (result)Examples List items
items //List(1, 2, 6, 4, 2, 1) (result)Sum of items
items.reduceRight(_+_) //16 (result)Product of items
items.reduceRight(_*_) //96 (result)As expression
items.map(_.toString).reduceRight("f(" + _ + ", " + _ + ")")f(1, f(2, f(6, f(4, f(2, 1)))))
List[Int]().reduceRight(_+_)
Exception:Nil.reduceRight
List[Int](0).reduceRight(_+_) //0 (result)
Nil //Nil is "The empty list." in Scala //List() (result)
List() //Empty list //List() (result)
List[AnyVal]() //List of numeric values //List() (result)
List.empty[AnyVal]//same as above //List() (result)
typeOf(Nil) //scala.collection.immutable.Nil.type (result)
typeOf(List()) //List[Nothing] (result)
typeOf(List[Nothing]()) //List[Nothing] (result)
typeOf(List[Any]()) //List of anything //List[Any] (result)
typeOf(List[String]()) //List of strings //List[String] (result)
typeOf(List.empty[String]) //List of strings //List[String] (result)
Nil == List() //true (result)
List() == List[AnyVal]() //true (result)
List[AnyVal]() == List.empty[AnyVal] //true (result)Lists of different types are equal if they're empty
List[Int]() == List[String]() //true (result)
val int_list = List(1, 2, 3)
typeOf(int_list) //List[Int] (result)List of Strings
val string_list = List("1", "2", "3")
typeOf(string_list) //List[String] (result)
val mixed_list_si = List("1", 2, "3")
typeOf(mixed_list_si) //List[Any] (result)List of Int's and Double's
val mixed_list_id = List(1, 2.0, 3)
typeOf(mixed_list_id) //List[Double] (result)List of Int's and BigInt's
val mixed_list_ibi = List(1, BigInt(2), 3)
typeOf(mixed_list_ibi) //List[Any] (result)
val items = List(1, 2, 3, 4.0)head of list (first element)
items.head // fast, complexity O //1.0 (result)head cannot be used on empty list
List().headOutput
Exception:java.util.NoSuchElementException: head of empty list
items(0) == items.head //true (result)last element (we must iterate all elements to get there)
items.last // slow, complexity N //4.0 (result)n-th element (we must iterate n elements to get there)
items(3) // slow, complexity N //4.0 (result)
items.size // slow, complexity N //4 (result)
items.length // slow, complexity N //4 (result)
val items_head::items_tail = items//this will create 2 val's
items_head //1.0 (result)
items_tail //List(2.0, 3.0, 4.0) (result)Empty list cannot be split (no head)
val empty_head::empty_tail = List()Output
Exception:scala.MatchError: List() (of class scala.collection.immutable.Nil$)
val empty_head::empty_tail = List[Int]()Output
Exception:scala.MatchError: List() (of class scala.collection.immutable.Nil$)
5 :: Nil == List[Int](5) //true (result)
val single_head::single_tail = List[Int](5)
single_head //5 (result)
single_tail //List() (result)
items //List(1.0, 2.0, 3.0, 4.0) (result)is equivalent to
1.0::(2.0::(3.0::(4.0::(Nil))))Output
List(1.0, 2.0, 3.0, 4.0)
items //List(1.0, 2.0, 3.0, 4.0) (result)Ignore 2 first elements, take the rest
items.drop(2) //fast //List(3.0, 4.0) (result)Take 3 first elements, ignore the rest
items.take(3) //fast //List(1.0, 2.0, 3.0) (result)
typeOf(items.take(3)) //List[Double] (result)drop and take work with empty lists
List().drop(2) //List() (result)
List().take(2) //List() (result)and with list smaller than given number of elements
items.drop(20) //empty //List() (result)
items.take(20) //all list //List(1.0, 2.0, 3.0, 4.0) (result)take n last elements
items.takeRight(4) //slow //List(1.0, 2.0, 3.0, 4.0) (result)
items.reverse.take(4) //slow //List(4.0, 3.0, 2.0, 1.0) (result)drop n last elements
items.dropRight(4) //slow //List() (result)
items.reverse.drop(4) //slow //List() (result)
def funny(x : Double) = x * 2
for(x <- 0 until items.length) yield funny(x)Output
Vector(0.0, 2.0, 4.0, 6.0)
def foo(l : List[Double]) : List[Double]= l match {
case Nil => Nil
case h::t => funny(h)::foo(t)
}
foo(items)OutputList(2.0, 4.0, 6.0, 8.0)
items.map(funny)Output
List(2.0, 4.0, 6.0, 8.0)
items.par.map(funny)Output
ParVector(2.0, 4.0, 6.0, 8.0)
items.zipWithIndexOutput
List((1.0,0), (2.0,1), (3.0,2), (4.0,3))
items.zipWithIndex.map {ei =>
var (element,index) = ei
"items[" + index + "]=" + element}OutputList(items[0]=1.0, items[1]=2.0, items[2]=3.0, items[3]=4.0)
items.zipWithIndex.map{case (item,index) => s"items[$index]=$item"}OutputList(items[0]=1.0, items[1]=2.0, items[2]=3.0, items[3]=4.0)
int_list //List(1, 2, 3) (result)
typeOf(int_list) //List[Int] (result)
string_list //List(1, 2, 3) (result)
typeOf(string_list) //List[String] (result)Join of two lists (list style)
int_list ::: string_list //List(1, 2, 3, 1, 2, 3) (result)
typeOf(int_list ::: string_list) //List[Any] (result)Join of two lists (universal style)
int_list ++ string_list //List(1, 2, 3, 1, 2, 3) (result)
int_list //List(1, 2, 3) (result)
typeOf(int_list) //List[Int] (result)list-style add as head
100::items //List(100, 1.0, 2.0, 3.0, 4.0) (result)
(100::items).head //100 (result)universal append as head
100+:items //List(100, 1.0, 2.0, 3.0, 4.0) (result)
(100+:items).head //100 (result)universal append as last
items:+200 //List(1.0, 2.0, 3.0, 4.0, 200) (result)
(items:+200).last //200 (result)
2+:List(3,7) //List(2, 3, 7) (result)is equivalent to
List(3,7).+:(2) //List(2, 3, 7) (result)but
List(3,7):+2 //List(3, 7, 2) (result)is equivalent to
List(3,7).:+(2) //List(3, 7, 2) (result)
List.make(4, 3) //List(3, 3, 3, 3) (result)Join list into String
List(5,2,1).mkString(" and ") //5 and 2 and 1 (result)
Join list into String with prefix and postfix
List(5,2,1).mkString("list contains ", " and ", ".") //list contains 5 and 2 and 1. (result)
Remove duplicates from list
List(1,1,0,1,1,0,0,1,2).distinct //List(1, 0, 2) (result)
0, 1, 1, 2, 3, 5, 8, 13, 21...
F(0)=0, F(1), F(2), F(3), ...
F(0), F(1), F(0) + F(1), F(1) + F(2), ...
0, 1, 1, 2, ...
//Fibonacci01.main(Array())
object Fibonacci01 extends App {
def fib(a : Int) : Int = {
if (a == 0) 0 else
if (a == 1) 1 else
return fib(a - 1) + fib(a - 2)
}
println(fib(35))
}
Code result()
9227465
//Fibonacci02.main(Array())
object Fibonacci02 extends App {
/**
* using match/case
*/
def fib(a : Int) : Int = {
a match {
case 0 => 0
case 1 => 1
case n => fib(n - 1) + fib(n - 2)
}
}
println(fib(35))
// but fib(-1) will throw java.lang.StackOverflowError
}
Code result()
9227465
//Fibonacci03.main(Array())
object Fibonacci03 extends App {
/**
* function using match/case with if
*/
def fib(a : Int) : Int = {
a match {
case 0 => 0
case 1 => 1
case n if (n > 1) => fib(n - 1) + fib(n - 2)
}
}
println(fib(35))
//fib(-1) throws scala.MatchError:
}
Code result()
9227465
//Fibonacci04.main(Array())
object Fibonacci04 extends App {
/**
* function using match/case with if
*/
def fib(a : Int) : Int = {
a match {
case 0 => 0
case 1 => 1
case n if (n > 1) => fib(n - 1) + fib(n - 2)
}
}
val numbers = 0 to 35 //for each number
val sequence : Seq = numbers.map(fib) //apply function fib
println(sequence) //Vector(0, 1, 1, 2, 3, 5, 8, 13, 21)
}
Code result()
Vector(0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229, 832040, 1346269, 2178309, 3524578, 5702887, 9227465)
//Fibonacci05.main(Array())
object Fibonacci05 extends App {
def fib : Stream = 0 #:: fib.scanLeft(BigInt(1))(_ + _)
val sequence : Seq = fib.take(36)
println(sequence.last)
}
Code result()
9227465