scala by luc duponcheel

Post on 18-Dec-2014

1.419 Views

Category:

Education

0 Downloads

Preview:

Click to see full reader

DESCRIPTION

Scala introduction given at BeJUG

TRANSCRIPT

Scala @ BeJUG

Luc DuponcheelImagineJ

September 2, 2009

Introduction

Chapter 0

Introduction

Types

I Scala is a (taste)fully typed language

Types

I Scala supports generic types

Expressions

I Scala is an expression oriented language

Objects

I Scala is an pure object oriented language

Functions

I Scala is a functional language

Scalable language

I Scala is a scalable languageI Scala does not grow on a language basisI Scala grows on a library basis

Usage

Chapter 1

Usage

Expression evaluation: Double

scala> 1.2.*(2.3)

res0: Double = 2.76

scala> 1.2 * 2.3

res1: Double = 2.76

Expression evaluation: String

scala> "Hello world".substring(2,9)

res2: java.lang.String = llo wor

scala> "Hello world" substring (2,9)

res3: java.lang.String = llo wor

Function result

def plus(x: Int) = (y: Int) => y + x

Function result

scala> :l plus.scala

Loading plus.scala...

plus: (x: Int)(Int) => Int

scala> plus(1)

res0: (Int) => Int = <function1>

Apply plus(1)

scala> plus(1).apply(1)

res1: Int = 2

scala> plus(1)(1)

res2: Int = 2

Function parameter

def applyToZero[X](f: Int => X) = f(0)

Function parameter

scala> :l applyToZero.scala

Loading applyToZero.scala...

applyToZero: [X]((Int) => X)X

scala> applyToZero (x => x + 1)

res0: Int = 1

Function parameter and result

def twice[X](f: X => X)

= (x: X) => f(f(x))

Function parameter and result

scala> :l twice.scala

Loading twice.scala...

twice: [X]((X) => X)(X) => X

scala> twice((x: Int) => x + 1)(0)

res0: Int = 2

Many parameter lists

def twice[X](f: X => X)(x: X) = f(f(x))

Function parameter and result

scala> :l twiceMany.scala

Loading twiceMany.scala...

twice: [X](f: (X) => X)(x: X)X

scala> twice((x: Int) => x + 1)(0)

res0: Int = 2

Placeholder syntax

scala> :l applyToZero.scala

Loading applyToZero.scala...

applyToZero: [X]((Int) => X)X

scala> applyToZero (_ + 1)

res0: Int = 1

Patterns

Chapter 2

Patterns

Compositional reuse

I Compositional reuse is reuse of

I code fragmentsthe building blocks, starting from atomic ones

I code templatesthe containers into which the building blockscan be plugged

Natural numbers and digits

type Nat = Int

type Dig = Int

Structural recursion

def structRec[A]

(a: A, op: (Dig, A) => A) : Nat => A = {

(n: Nat) =>

if(n == 0) {

a

} else {

op(n % 10, structRec(a, op)(n / 10))

}

}

Using structural recursion

def sumOfDigits =

structRec[Int](0, _ + _)

def hasDigit(d: Dig) =

structRec[Boolean](false, _ == d || _)

def exists(p: Dig => Boolean) =

structRec[Boolean](false, p(_) || _)

Using structural recursion

scala> sumOfDigits(1234)

res0: Int = 10

scala> hasDigit(2)(1234)

res1: Boolean = true

scala> exists(_ == 2)(1234)

res2: Boolean = true

unfoldAndThenFold

6

---- | / \ |

| dig = 3 + 3 = rec |

-----------------------

| 2 + 1 |

| / \ |

| 1 + 0 |

| / \ |

| 0 0 |

List of digits

:

/ \

3 :

/ \

2 :

/ \

1 :

/

0

Sum of list of digits

+

/ \

3 +

/ \

2 +

/ \

1 +

/ \

0 0

Tail recursion

def tailRec[A]

(a: A, op: (Dig, A) => A) : Nat => A = {

(n: Nat) =>

if(n == 0) {

a

} else {

tailRec(op(n % 10, a), op)(n / 10)

}

}

Using tail recursion

def sumOfDigits =

tailRec[Int](0, _ + _)

def hasDigit(d: Dig) =

tailRec[Boolean](false, _ == d || _)

def exists(p: Dig => Boolean) =

tailRec[Boolean](false, p(_) || _)

Using tail recursion

scala> sumOfDigits(1234)

res0: Int = 10

scala> hasDigit(2)(1234)

res1: Boolean = true

scala> exists(_ == 2)(1234)

res2: Boolean = true

iterateAndAccumulate

6 = rec

| / \ |

| 0 6 |

| / \ |

| 1 + 5 |

| ------------

| 2| + 3 = acc |

--------| / \ |

| dig = 3 + 0 |

Control

Chapter 3

Control

Conditional construct

def _if

(cond: Boolean)

(block: () => Unit)

= cond match {

case true => block()

case false => ()

}

Conditional expression

scala> :l if.scala

Loading if.scala...

_if: (Boolean)(() => Unit)Unit

scala> _if(Math.random<0.5)(() =>

| println("ok")

| )

ok

Loop construct

def _while

(cond: () => Boolean)

(block: () => Unit): Unit

= if(cond()) {

block()

_while(cond)(block)

}

Loop expression

scala> :l while.scala

Loading while.scala...

_while: (() => Boolean)(() => Unit)Unit

scala> _while(() => Math.random<0.5)(() =>

| println ("ok")

| )

ok

Conditional construct

def _if

(cond: Boolean)

(block: => Unit)

= cond match {

case true => block

case false => ()

}

Loop construct

def _while

(cond: => Boolean)

(block: => Unit): Unit

= if(cond) {

block

_while(cond)(block)

}

Conditional expression

scala> :l if_cbn.scala

Loading if_cbn.scala...

_if: (Boolean)(=> Unit)Unit

scala> _if(Math.random<0.5) {

| println ("ok")

| }

ok

Loop expression

scala> :l while_cbn.scala

Loading while_cbn.scala...

_while: (=> Boolean)(=> Unit)Unit

scala> _while(Math.random<0.5) {

| println ("ok")

| }

ok

Types

Chapter 4

Types

Instance constants

class C {

val re = 0.0

val im = 0.0

}

Instance constants: usage

scala> :l complex01.scala

Loading complex01.scala...

defined class C

scala> new C

res0: C = C@151fe8a

toString

class C {

// ...

override def toString

= re + " + " + im + "*" + "i"

}

toString: usage

scala> :l complex02.scala

Loading complex02.scala...

defined class C

scala> new C

res0: C = 0.0 + 0.0*i

Class parameters

class C(r: Double, i: Double) {

val re = r

val im = i

// ...

}

Class parameters: usage

scala> :l complex03.scala

Loading complex03.scala...

defined class C

scala> new C(-1, -1)

res0: C = -1.0 + -1.0*i

toString again

override def toString = {

val sgnim = if(im<0.0){" - "}else{" + "}

val absim = if(im<0.0){ -im }else{ im }

if(im == 0.0) { re + "" } else {

if(re == 0.0) { im + "*i" } else {

re + sgnim + absim + "*i" } }

}

toString again: usage

scala> :l complex04.scala

Loading complex04.scala...

defined class C

scala> new C(-1, -1)

res0: C = -1.0 - 1.0*i

scala> new C(-1, +1)

res1: C = -1.0 + 1.0*i

Additive operators

class C(r: Double, i: Double) {

// ...

def +(c: C) =

new C(re + c.re, im + c.im)

def -(c: C) =

new C(re - c.re, im - c.im)

// ...

}

Additive operators: usage

scala> :l complex05.scala

Loading complex05.scala...

defined class C

scala> new C(+1,+1) + new C(-3,+2)

res1: C = -2.0 + 3.0*i

scala> new C(+1,+1) - new C(-3,+2)

res2: C = 4.0 - 1.0*i

Multiplicative operators

// ...

def *(c: C) = new C(re*c.re - im*c.im,

im*c.re + re*c.im)

def /(c: C) = {

val d = c.re*c.re + c.im*c.im

new C((re*c.re + im*c.im) / d,

(im*c.re - re*c.im) / d) }

// ...

Multiplicative operators: usage

scala> :l complex06.scala

Loading complex06.scala...

defined class C

scala> new C(+1,+1) * new C(-3,+2)

res0: C = -5.0 - 1.0*i

scala> new C(-5,-1) / new C(-3,+2)

res1: C = 1.0 + 1.0*i

Negation operator

class C(r: Double, i: Double) {

// ...

def unary_- = new C(-re, -im)

// ...

}

Negation operator: usage

scala> :l complex07.scala

Loading complex07.scala...

defined class C

scala> - new C(-5,-1)

res0: C = 5.0 + 1.0*i

scala> - new C(5,1)

res1: C = -5.0 - 1.0*i

The complex number i

class C(r: Double, i: Double) {

// ...

}

object C {

val i = new C(0.0, 1.0)

}

The complex number i: usage

scala> :l complex08.scala

Loading complex08.scala...

...

scala> import C.i

import C.i

scala> i * i

res0: C = -1.0

Converting Double

class C(r: Double, i: Double) {

// ...

}

object C {

//...

implicit def toC(d: Double)

= new C(d, 0.0)

}

Converting Double: usage

scala> :l complex09.scala

Loading complex09.scala...

...

scala> (1.0 + 1.0*i) / i

res0: C = 1.0 - 1.0*i

scala> 1.0 + 1.0*i / i

res1: C = 2.0

Spaces

Chapter 5

Spaces

Space

class Space[X] extends Actor {

// ...

}

Worker

abstract class Worker[X](space: Space[X])

extends Actor {

// ...

}

Work

object Types {

type Work[X] = PartialFunction[X,Unit]

}

Put and Reg

case class Put[X](x: X)

case class Reg[X](

work: Work[X]

worker: Worker[X])

App

case class App[X](work: Work[X], x: X)

Space information

private var ps: List[Put[X]] = Nil

private var rs: List[Reg[X]] = Nil

Space functionality: part one

I A worker can put objects x into the space

using space ! Put(x)

I A worker can register work with the space

using space ! Reg(work, worker)

Space functionality: part two

I A space can notify a worker when an objectx, to which the work he registered with thespace can be applied, has been put into thespace using worker ! App(work, x)

reacting to a Put: part one

case p@Put(x: X) => {

val frs =

rs filter(r => r.work.isDefinedAt(x)

if(frs == Nil) {

ps ::= p.asInstanceOf[Put[X]]

}

reacting to a Put: part two

else {

val fr = frs.last

rs = rs filter (r => !(r eq fr))

fr.worker ! App(fr.work, x)

}

reacting to a Reg: part one

case r@Reg(work, worker) => {

val fps =

ps filter (p => work.isDefinedAt(p.x))

if(fps == Nil) {

rs ::= r.asInstanceOf[Reg[X]]

}

reacting to a Reg: part two

else {

val fp = fps.last

ps = ps filter (p => !(p eq fp))

worker ! App(work, fp.x)

}

Worker: part one

abstract class Worker[X](space: Space[X])

extends Actor {

protected var isAcceptingMoreWork = true

protected def registerForWork()

def put(x: X) {

space ! Put(x) }

def reg(work: Work[X]) {

space ! Reg(work, this) }

Worker: part two

private def applyZeroOrMoreTimes() {

loop { react {

case App(work, x) => {

work.apply(x)

if(isAcceptingMoreWork) {

registerForWork()

} } } }

}

Worker: part three

private def applyOneOrMoreTimes() {

registerForWork()

applyZeroOrMoreTimes()

}

Worker: part four

def act() {

applyOneOrMoreTimes()

}

PingPong

sealed abstract class PingPong

case object Ping extends PingPong

case object Pong extends PingPong

case object Over extends PingPong

case object Done extends PingPong

Player

abstract class Player(

name: String

table: Space[PingPong]

)

extends Worker[PingPong](table) {

override def toString = name

}

Pinger: part one

protected def registerForWork() =

reg {

case Pong => {

if (Math.random < 0.95) {

println(this + " ping")

put(Ping)

} else {

put(Over)

}

Pinger: part two

case Done => {

println(this + " stop")

isAcceptingMoreWork = false

}

}

}

}

Ponger: part one

protected def registerForWork() =

reg {

case Ping => {

if (Math.random < 0.95) {

println(this + " pong")

put(Pong)

} else {

put(Over)

}

Ponger: part two

case Done => {

println(this + " stop")

isAcceptingMoreWork = false

}

}

}

}

Umpire: part one

class Umpire(

name: String,

players: List[Player],

table: Space[PingPong])

extends Worker[PingPong](table) {

override def toString = name

Umpire: part two

protected def registerForWork() =

reg {

case Over => {

println(this + " done")

for { _ <- players } put(Done)

println(this + " stop")

isAcceptingMoreWork = false

}

}

theTable

class Table extends Space[PingPong]

val theTable = new Table

thePlayers

val thePlayers =

Pinger("pinger_1", true) ::

Pinger("pinger_2", false) ::

Ponger("ponger_1") ::

Ponger("ponger_2") ::

Nil

theUmpire

val theUmpire =

new Umpire

("_umpire_", thePlayers, theTable)

main

theTable.start

thePlayers.foreach(_.start)

theUmpire.start

val startPinger = thePlayers.head

startPinger.put(Ping)

top related