Introduction à Scala - Michel Schinz - January 2010
-
Upload
jug-lausanne -
Category
Technology
-
view
107 -
download
1
description
Transcript of Introduction à Scala - Michel Schinz - January 2010
![Page 1: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/1.jpg)
an introductionMichel Schinz
![Page 2: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/2.jpg)
What is Scala?Scala is a programming language that:
• coherently combines the best aspects of object-oriented and functional programming languages,
• runs on the JVM and is fully interopeable with Java – a .NET version is in the works,
• is statically typed and very concise,
• offers a high level of abstraction and good performances.
![Page 3: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/3.jpg)
Object-oriented programming in Scala
![Page 4: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/4.jpg)
Rational numbers
First example: model rational numbers n / d where n and d are integers, and d ≠ 0.
Provide addition, multiplication and comparison of rationals.
![Page 5: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/5.jpg)
A class for rationals (1)class Rational(n0: Int, d0: Int) { require(d0 != 0)
private def gcd(x: Int, y: Int): Int = if (y == 0) x else gcd(y, x % y)
private val g = gcd(n0.abs, d0.abs) val n: Int = n0 / g val d: Int = d0 / g
def this(n: Int) = this(n, 1)
to be continued…auxiliary
constructor
public fields (immutable)
constructor arguments
no explicit type (Int inferred)no return
![Page 6: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/6.jpg)
A class for rationals (2) …continued
def +(that: Rational): Rational = new Rational(this.n * that.d + that.n * this.d, this.d * that.d)
def *(that: Rational): Rational = new Rational(this.n * that.n, this.d * that.d)
override def toString: String = n +"/"+ d} parameterless
method
public method
![Page 7: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/7.jpg)
Using rationalsscala> val r1 = new Rational(1, 3)r1: Rational = 1/3
scala> val r2 = new Rational(5)r2: Rational = 5/1
scala> r1 + r2 // or: r1.+(r2)res0: Rational = 16/3
scala> res0 * r1 // or: res0.*(r1)res1: Rational = 16/9
primary constructor call
auxiliary constructor call
inferred type
![Page 8: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/8.jpg)
A companion for rationals
object Rational { def apply(n: Int, d: Int): Rational = new Rational(n, d) def apply(n: Int): Rational = new Rational(n)
val ZERO = new Rational(0)}
singleton
scala> Rational(2,5) + Rational.ZEROres1: Rational = 2/5
implicitly calls apply
companion object for class Rational
![Page 9: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/9.jpg)
Ordered objects
trait Ordered[T] { def compare(that: T): Int def < (that: T): Boolean = (this compare that) < 0 def <=(that: T): Boolean = (this compare that) <= 0 def > (that: T): Boolean = (this compare that) > 0 def >=(that: T): Boolean = (this compare that) >= 0}
abstract method
type parameter
![Page 10: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/10.jpg)
Ordered rationals
class Rational(n0: Int, d0: Int) extends Ordered[Rational] { … as before
def compare(that: Rational): Int = (n * that.d) compare (that.n * d)}
provides <, <=, > and >= methods
![Page 11: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/11.jpg)
Cells
Second example: model mutable cells that contain a single value of some arbitrary type.
Additionally, define logging and undoable variants.
![Page 12: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/12.jpg)
A class for generic cells
class Cell[T](val init: T) { private var v = init
def get(): T = v def set(v1: T): Unit = { v = v1 }
override def toString: String = "Cell("+ v +")"}
make init available as a field
mutable field
≈ Java’s void
![Page 13: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/13.jpg)
A trait for logging cellstrait LoggingCell[T] extends Cell[T] { override def get(): T = { println("getting "+ this) super.get() }
override def set(v1: T): Unit = { println("setting "+ this +" to "+ v1) super.set(v1) }}
![Page 14: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/14.jpg)
A trait for undoable cellstrait UndoableCell[T] extends Cell[T] { import collection.mutable.ArrayStack private var hist = new ArrayStack[T]()
override def set(v1: T): Unit = { hist.push(super.get()) super.set(v1) }
def undo(): Unit = super.set(hist pop)}
![Page 15: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/15.jpg)
Mixin composition
new Cell(0)
new Cell(0) with LoggingCell[Int]
new Cell(0) with LoggingCell[Int] with UndoableCell[Int]
new Cell(0) with UndoableCell[Int] with LoggingCell[Int]
basic integer cell
logging integer cell
logging, undoable integer cell (undos are
logged)
logging, undoable integer cell (undos are
not logged)
![Page 16: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/16.jpg)
The Scala library
![Page 17: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/17.jpg)
Optional valuesAn optional value is either empty, or contains a single element.
Example use: as a clean replacement for null.
abstract class Option[+T] { def isEmpty: Boolean def get: T
def getOrElse[U >: T](d: =>U): U = if (isEmpty) d else get
…many more methods}
by-name parameter
bounded type parameter
variance (here co-variant)
![Page 18: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/18.jpg)
Optional values (2)
case class Some[+T](x: T) extends Option[T] { def isEmpty = false def get = x}
case object None extends Option[Nothing] { def isEmpty = true def get = throw new …}
subtype of all types
can be matched (see later) & compiler-provided methods
![Page 19: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/19.jpg)
Using optional values
scala> val v1 = Some("something")v1: Some[String] = Some(something)
scala> val v2 = Nonev2: None.type = None
scala> v1 getOrElse "nothing"res1: String = something
scala> v2 getOrElse "nothing"res2: String = nothing
compiler-provided factory method
compiler-provided toString method
![Page 20: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/20.jpg)
TuplesA tuple of size n contains exactly n heterogenous elements – i.e. they can be of different types.
Example use: a function that has to return n values can return them wrapped in a single tuple.
case class Tuple2[+T1,+T2]( _1: T1, _2: T2)
case class Tuple3[+T1,+T2,+T3]( _1: T1, _2: T2, _3: T3)
etc.
![Page 21: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/21.jpg)
Short tuple syntaxScala offers syntactic shortcuts for tuple values:
(e1, …, en) ≣ Tuplen(e1, …, en)
and for tuple types:
(T1, …, Tn) ≣ Tuplen[T1, …, Tn]
Example:
scala> val p = ("Orwell", 1984)p: (String, Int) = (Orwell,1984)scala> p._1res1: String = Orwell
arguments of case classes are fields
![Page 22: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/22.jpg)
(Im)mutable collections
Options and tuples are immutable.
Standard collections (sequences, sets, maps) are provided in mutable and immutable variants.
Mutable collections are similar to the ones found in Java and other imperative languages.
Immutable collections are similar to the ones found in typical functional languages.
![Page 23: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/23.jpg)
Immutable listsAn immutable list is either empty or composed of a head element and a tail, which is another list.
abstract class List[+T] { def isEmpty: Boolean def head: T def tail: List[T] def ::[U >: T](x: U): List[U] = new ::[U](x, this)
…many more methods}
![Page 24: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/24.jpg)
Immutable lists (2)case class ::[T](val head: T, val tail: List[T]) extends List[T] { def isEmpty = false }
case object Nil extends List[Nothing] { def isEmpty = true def head: Nothing = throw new … def tail: List[Nothing] = throw new …}
![Page 25: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/25.jpg)
Sequences, maps and setsscala> val aSeq = Seq("zero","one","two")scala> aSeq(1)res1: String = one
scala> val aMap = Map("zero" -> 0, "one" -> 1, "two" -> 2)scala> aMap("one")res2: Int = 1
scala> val aSet = Set("zero","one","two")scala> aSet("one")res3: Boolean = true
![Page 26: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/26.jpg)
For loopsFor loops enable iteration over the elements of collections, using a syntax that is reminiscent of SQL queries.
for (user <- users if (user.isMale && user.age > 30)) yield user.name
![Page 27: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/27.jpg)
Pattern matching
![Page 28: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/28.jpg)
Pattern matching
Instances of case classes can easily be constructed:
scala> Some((1,2))res: Some[(Int,Int)] = Some((1,2))
Pattern matching makes deconstruction of case classes similarly easy.
![Page 29: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/29.jpg)
Integer division
def divMod(n: Int, d: Int): Option[(Int,Int)] = { if (d == 0) None else { …compute quotient q and remainder r Some((q, r)) }}
![Page 30: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/30.jpg)
Using integer divisiondef testDivMod(n: Int, d: Int) = divMod(n, d) match { case Some((q, r)) => println("quot: "+ q +" rem: "+ r) case None => println("<no result>") }
scala> testDivMod(5, 3)quot: 1 rem: 2scala> testDivMod(5, 0)<no result>
![Page 31: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/31.jpg)
Pattern matching lists
def sum(l: List[Int]): Int = l match { case h :: t => h + sum(t) case Nil => 0}
Since lists are recursive, it is natural to manipulate them with recursive functions.
Furthermore, since they are defined as a disjunction of two cases (non-empty / empty list), it is natural to use pattern matching to do a case analysis.
Example: a function to sum a list of integers.
![Page 32: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/32.jpg)
Typed patternsPattern matching can also be used to discriminate on the type of a value:
def succAny(x: Any): Any = x match { case i: Int => i + 1 case l: Long => l + 1 case other => other}
scala> succAny(2)res1: Any = 3scala> succAny("two")res2: Any = two
supertype of all types
Int and Long are not case classes
![Page 33: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/33.jpg)
Exception handlingUnsurprisingly, exception handling is done using pattern matching:
try { val f = new FileInputStream("f.txt") println(f.read()) f.close()} catch { case _: FileNotFoundException => println("not found") case e: IOException => println("other error: " + e)}
_ is a wildcard
![Page 34: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/34.jpg)
Functional programming in Scala
![Page 35: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/35.jpg)
What is FP?
The functional style of programming is one that relies on mathematical functions as the basic building block of programs.
In mathematics, a function always returns the same result when applied to the same arguments.
Therefore, the functional style of programming strongly discourages the use of side-effects – i.e. variables and other kinds of mutable data.
![Page 36: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/36.jpg)
What is a FPL?A functional programming language is one that encourages the functional style of programming by:
• offering first-class functions that can be manipulated like any other value,
• providing lightweight syntax to define arbitrarily-nested functions,
• discouraging the use of side-effects, for example by providing libraries of immutable data-structures.
![Page 37: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/37.jpg)
Why is FP interesting?Side-effects complicate several classes of programs, like:
• concurrent programs with shared, mutable state,
• programs that need to do “time travel”, e.g. interactive programs with undo, SCMs, …
• programs that need to work on a consistent state of some data, e.g. a live backup program,
• etc.
![Page 38: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/38.jpg)
A trait for functionstrait Function1[F, T] { f => def apply(x: F): T
def compose[F2](g: Function1[F2, F]) : Function1[F2, T] = new Function1[F2, T] { def apply(x: F2): T = f.apply(g.apply(x)) }
override def toString = "<fun>"}
new name for this
![Page 39: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/39.jpg)
Using functions as valuesscala> val succ = new Fun[Int,Int] { def apply(x: Int) = x + 1 }succ: …with Function1[Int,Int] = <fun>scala> val twice = new Fun[Int,Int] { def apply(x: Int) = x + x }twice: …with Function1[Int,Int] =<fun>scala> succ.apply(6)res1: Int = 7scala> twice.apply(5)res2: Int = 10scala> (succ compose twice).apply(5)res3: Int = 11
![Page 40: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/40.jpg)
Using functions as valuesscala> val succ = new Fun[Int,Int] { def apply(x: Int) = x + 1 }succ: …with Function1[Int,Int] = <fun>scala> val twice = new Fun[Int,Int] { def apply(x: Int) = x + x }twice: …with Function1[Int,Int] =<fun>scala> succ.apply(6)res1: Int = 7scala> twice.apply(5)res2: Int = 10scala> (succ compose twice).apply(5)res3: Int = 11W
orks
, but
way to
o verb
ose!
![Page 41: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/41.jpg)
Functional syntactic sugar
scala> val succ = { x: Int => x + 1 }succ: (Int) => Int = <function1>
scala> val twice = { x: Int => x + x }twice: (Int) => Int = <function1>
scala> (succ compose twice)(5)res1: Int = 11
anonymous function
a.k.a. Function1[Int, Int]
implicit apply
![Page 42: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/42.jpg)
Partial applicationFunction values can also be created by applying existing functions or methods to a (possibly empty) subset of their arguments:
scala> val succ: Int=>Int = _ + 1succ: (Int) => Int = <function1>
scala> val toStr: Any=>String = _.toStringtoStr: (Any) => String = <function1>
scala> toStr(0123)res0: String = 83
![Page 43: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/43.jpg)
Collections as functions
Most collections are functions:
• Seq[T] has type Int=>T,
• Map[K,V] has type K=>V,
• Set[T] has type T=>Boolean.
This explains the common notation to access their elements: it’s simply function application!
![Page 44: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/44.jpg)
Operating on collectionsFunctional values are ideal to operate on collections. Examples:scala> val s = Seq(1,2,3,4,5)scala> s map (_ + 1)res1: Seq[Int] = List(2, 3, 4, 5, 6)scala> s reduceLeft (_ * _)res2: Int = 120scala> s filter (_ % 2 == 0)res3: Seq[Int] = List(2, 4)scala> s count (_ > 3)res4: Int = 2scala> s forall (_ < 10)res5: Boolean = true
![Page 45: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/45.jpg)
Project Euler: problem 8
![Page 46: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/46.jpg)
Solving problem 8val n = "7316717653133062491922511967442…"val digits = s.toList map (_.asDigit)
def prods(l: List[Int]): List[Int] = l match { case a :: (t@(b :: c :: d :: e :: _)) => (a * b * c * d * e) :: prods(t) case _ => List() }
prods(digits) reduceLeft (_ max _)
![Page 47: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/47.jpg)
For loops translationThe for notation is pure syntactic sugar. The example:
for (user <- users if (user.isMale && user.age > 30)) yield user.name
is automatically expanded to:users .filter(user => user.isMale && user.age > 30) .map(user => user.name)
![Page 48: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/48.jpg)
Implicits
![Page 49: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/49.jpg)
Scala implicits
Scala offers two notions of implicit entities that are automatically inserted by the compiler in certain contexts:
• Implicit conversions, which can be applied automatically to transform a type-incorrect expression into a type-correct one.
• Implicit parameters, which can be automatically passed to a function.
![Page 50: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/50.jpg)
Implicit conversionsAn implicit conversion from Int to Rational can be added to the latter’s companion object:
object Rational { …as before implicit def i2r(i: Int): Rational = Rational(i)}
scala> 2 + Rational(1,3) // i2r(2) + …res2: Rational = 7/3scala> Rational(1,3) + 3 // … + i2r(3)res3: Rational = 10/3
![Page 51: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/51.jpg)
“Pimp my library”Implicit conversions make it possible to “augment” existing classes by implicitly wrapping them – known as the Pimp my library pattern.
This technique is heavily used in the standard library to improve anemic Java classes (e.g. String, Integer, Boolean, arrays, etc.).
scala> "1337"res1: java.lang.String = 1337
scala> "1337".toIntres2: Int = 1337
strings are really Java strings
implicit conversion
![Page 52: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/52.jpg)
Implicit parameters
def max[T](xs: T*) (implicit ord: Ordering[T]): T = xs reduceLeft ord.max
scala> max(4, -2, 12, 25, 7, -1, 2)res1: Int = 25scala> max(4, -2, 12, 25, 7, -1, 2) (Ordering.Int.reverse)res2: Int = -2scala> max(1 to 20 : _*)res3: Int = 20
repeated parameter
implicitly Ordering.Int
pass all elements as separate arguments
![Page 53: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/53.jpg)
Working with XML data
![Page 54: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/54.jpg)
XML literalsScala supports XML literals, which are translated to instances of various classes in scala.xml.
scala> val hello = <p>Hello <b>world</b></p>hello: scala.xml.Elem = <p>Hello <b>world</b></p>scala> val name = "Roger&Co."name: java.lang.String = Roger&Co.scala> val hello = <p>Hello <b>{ name }</b></p>hello: scala.xml.Elem = <p>Hello <b>Roger&Co.</b></p>
arbitrary Scala expression
![Page 55: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/55.jpg)
XPath-like queriesscala> val users = <users> <user name="Roger" age="12"/> <user name="Mary" age="44"/> <user name="Jean" age="12"/> </users>scala> users \\ "@name"res1: scala.xml.NodeSeq = RogerMaryJeanscala> (users \\ "@age") map (_.toString.toInt) reduceLeft (_ max _)res2: Int = 44
![Page 56: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/56.jpg)
XML pattern matchingdef parseRow(r: xml.Node): (String, Int) = r match { case <tr><td>{ name }</td> <td>{ age }</td></tr> => (name.text, age.text.toInt) }
scala> val table = <table> <tr><td>Roger</td><td>12</td></tr> <tr><td>Mary</td><td>44</td></tr> </table>scala> (table \ "tr") map parseRowres1: Seq[(String, Int)] = List((Roger,12), (Mary,44))
![Page 57: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/57.jpg)
Testing with ScalaCheck
![Page 58: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/58.jpg)
Properties for rationalsThe operations we defined on rationals should satisfy several properties:
• ∀x, y ∈ Q: x + 0 = 0 + x = x
• ∀x, y ∈ Q: x + (y + z) = (x + y) + z
• etc.
ScalaCheck makes it possible to express such properties and test them on random rationals. Extensive use of implicits keep the client code very concise.
![Page 59: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/59.jpg)
Properties for rationals
object RatProps extends Properties("Rat") { property("+ left unit") = Prop.forAll((x: Rational) => 0 + x == x) property("+ right unit") = Prop.forAll((x: Rational) => x + 0 == x) property("+ associativity") = Prop.forAll((x: Rational, y: Rational, z: Rational) => (x + y) + z == x + (y + z))}
![Page 60: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/60.jpg)
Generating rationalsScalaCheck doesn’t know how to generate arbitrary rationals, but we can easily define a generator for them:
implicit def arbRat: Arbitrary[Rational] = Arbitrary { Gen.sized(sz => for (n <- Gen.choose(-sz, sz); d <- Gen.choose(-sz, sz) suchThat (_ != 0)) yield Rational(n, d)) }
![Page 61: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/61.jpg)
Testing rationals% scala RatProps + Rat.+ left unit: OK, passed 100 tests. + Rat.+ right unit: OK, passed 100 tests. + Rat.+ associativity: OK, passed 100 tests.
! Rat.wrong: Falsified after 0 passed tests. > ARG_0: 1/2
When a property can be falsified (here the incorrect property ∀x ∈ Q: x = 0), the counter-example is presented:
![Page 62: Introduction à Scala - Michel Schinz - January 2010](https://reader033.fdocuments.us/reader033/viewer/2022042613/54c893474a795943258b45af/html5/thumbnails/62.jpg)
Further reading
http://www.scala-lang.org/
Two books about Scala:
• Programming in Scala by Odersky, Spoon & Venners
• Programming Scala by Wampler & Payne
One book about functional programming:
• The Functional Approach to Programming by Cousineau, Mauny & Callaway