Scala: Functioneel programmeren in een object georiënteerde wereld

48
Scala Functioneel programmeren in een object geörienteerde wereld Werner Hofstra

Transcript of Scala: Functioneel programmeren in een object georiënteerde wereld

Page 1: Scala: Functioneel programmeren in een object georiënteerde wereld

ScalaFunctioneel programmeren

in een object geörienteerde wereld

Werner Hofstra

Page 2: Scala: Functioneel programmeren in een object georiënteerde wereld

Over mij• Werner Hofstra • Software dev @ Enshore • Java, Scala, Clojure, …

Page 3: Scala: Functioneel programmeren in een object georiënteerde wereld

Wie is bekend met

• Java

• Object georiënteerd programmeren

• Functioneel programmeren

• Scala

Page 4: Scala: Functioneel programmeren in een object georiënteerde wereld

Functioneel programmeren

• Focus op (pure) functies

• Vermijden van side effects

• Immutability

• Vermijden van (re)assignment

Page 5: Scala: Functioneel programmeren in een object georiënteerde wereld

Scala• Static typing

• Object georiënteerd

• Functioneel

• Compileert naar Java bytecode

• Pattern matching

Page 6: Scala: Functioneel programmeren in een object georiënteerde wereld

Beloftes

• Elegant

• Expressief

• Concurrency

• Samensmelten OO en FP

Page 7: Scala: Functioneel programmeren in een object georiënteerde wereld

Wie gebruikt Scala?

Page 8: Scala: Functioneel programmeren in een object georiënteerde wereld

Syntaxobject Sounds extends App { Animal dog = new Dog("Beike") println(s"Dog: ${dog.name}") println(dog.makeSound) }

trait Animal { def makeSound: String }

class Dog(val name: String) extends Animal { override def makeSound: String = s"$name says WOOF!" }

public class Sounds { public static void main(String[] args) { Animal dog = new Dog("Beike"); System.out.println("Dog: " + dog.getName()); System.out.println(dog.makeSound()); } }

interface Animal { String makeSound(); }

class Dog extends Animal { private String name;

public Dog(String name) { this.name = name; }

@Override public String makeSound() { return getName() + " says WOOF!"; }

public String getName() { return name; } }

Page 9: Scala: Functioneel programmeren in een object georiënteerde wereld

Basis• var • val • def • if • for • while

val fordTColor = "Black"

var peugeotColor = "Blue" peugeotColor = "Gray"

val ferrariColor = if (ferrari.isRed) "Red" else "Yellow"

val colors = Array( "Blue", "Black", "Gray", "White", )

def printAllColors: Unit = { for (color <- colors) { println(color) } }

Page 10: Scala: Functioneel programmeren in een object georiënteerde wereld

Waarden en variabelen

• variable • value

val one = 1 one = 2 // Compileert niet

val oneToFive = 1 to 5

val twoToSix = oneToFive map { _ + 1 }

var two = 2 two = 1 // Ok, maar raar

Page 11: Scala: Functioneel programmeren in een object georiënteerde wereld

Immutability

• 4 + 5 = 9

• 4 += 1

• Math.pi = 0

• werner = peter

• Time.now() += 2 hours

Page 12: Scala: Functioneel programmeren in een object georiënteerde wereld

Object Oriented

Programming• Alles is een object

1 + 2

1.+(2)

"hello".endsWith("lo")

"hello" endsWith "lo"

Page 13: Scala: Functioneel programmeren in een object georiënteerde wereld

Object Oriented Programming

• Alles is een object

• Classes

class Person(val name: String, val age: Int)

Page 14: Scala: Functioneel programmeren in een object georiënteerde wereld

Object Oriented Programming• Alles is een object

• Classes

• Traits

class Person(val name: String, val age: Int)

trait InsaneSkills { def listSkills: List(String) }

Page 15: Scala: Functioneel programmeren in een object georiënteerde wereld

Object Oriented Programming

• Alles is een object

• Classes

• Traits

• Inheritance

class Person(val name: String, val age: Int)

trait InsaneSkills { def listSkills: List(String) }

class Programmer( override val name: String, override val age: Int, language: String) extends Person(name, age) with InsaneSkills {

def listSkills = List( s"Programming ${language}", "Giving talks") }

Page 16: Scala: Functioneel programmeren in een object georiënteerde wereld

Traits

• Interfaces

• Implementaties

• Mixins

trait Logger { def log(msg: String): Unit = {} }

trait PrintLogger extends Logger { override def log(msg: String): Unit = println(msg) }

class CoffeeMaker extends Logger { def brew(kind: String): Unit = log(s"Brewing coffee: $kind") }

val silently = new CoffeeMaker silently brew "espresso" // (geen output)

val loudly = new CoffeeMaker with PrintLogger loudly brew "espresso" // Brewing coffee: espresso

Page 17: Scala: Functioneel programmeren in een object georiënteerde wereld

Singletons• Slechts 1 instantie

• Voor static methoden

• Geen constructor args

object MyRandom { import scala.util.Random

def nextIntBetween(from: Int, to: Int): Int = Random.nextInt(to - from) + from }

Page 18: Scala: Functioneel programmeren in een object georiënteerde wereld

Types• Type inference • Static types

// hello :: String val hello = "Hello"

// world :: String val world: String = "World"

// strings :: List[String] val strings = List(hello, world)

// werner :: Programmer val werner = new Programmer( "werner", 28, "Scala")

Page 19: Scala: Functioneel programmeren in een object georiënteerde wereld

Tuples

// tuple :: (Int, String) val tupleOne = (1, "one")

// tupleTwo :: (Programmer, (Int, String)) val tupleTwo = (werner, tupleOne)

Page 20: Scala: Functioneel programmeren in een object georiënteerde wereld

Functies• ‘First class citizens’

• Hebben ook types

// addOne :: Int => Int def addOne(x: Int) = x + 2

// addLengths :: (String, String) => Int def addLengths(s1: String, s2: String) = s1.length + s2.length

// addLengths2 :: String => (String => Int) def addLengths2(s1: String)(s2: String) = s1.length + s2.length

Page 21: Scala: Functioneel programmeren in een object georiënteerde wereld

Anonieme functies

• Functies zonder naam • Handig voor HOF

val add = (x: Int, y: Int) => x + y

add(1, 2) // 3

Page 22: Scala: Functioneel programmeren in een object georiënteerde wereld

Hogere orde functies

• Functies in argumenten • Functies uit functies

Page 23: Scala: Functioneel programmeren in een object georiënteerde wereld

Hogere orde functies• Functies uit functies

// makeAdder :: Int => (Int => Int) val makeAdder = { x: Int => { y: Int => x + y } }

// add5 :: Int => Int val add5 = makeAdder(5)

// eleven :: Int val eleven = add5(6) // 11

Page 24: Scala: Functioneel programmeren in een object georiënteerde wereld

Hogere orde functies

• Functies uit functies

• Functies in argumenten

def foreach(fn: Int => Unit, xs: List[Int]) = for (x <- xs) fn(x)

foreach(println, List(1, 2, 3))

Page 25: Scala: Functioneel programmeren in een object georiënteerde wereld

Hogere orde functies

val strings = List("one", "two", "three")

strings map { str => str.toUpperCase } // List("ONE", "TWO", "THREE")

strings filter { _.length == 3 } // List("one", "two")

strings.foldLeft("zero") { _ + " " + _ } // "zero one two three"

strings foreach println // ()

Page 26: Scala: Functioneel programmeren in een object georiënteerde wereld

Hogere orde functiesval strings = List("one", "two", "three") val numbers = List(1, 2, 3)

(numbers zip strings).toMap // Map(1 -> "one", 2 -> "two", 3 -> "three")

strings partition { _.length < 4 } // (List("one", "two"), List("three"))

strings takeWhile { _.length < 4 } // List("one", "two")

strings dropWhile { _.length < 4 } // List("three")

Page 27: Scala: Functioneel programmeren in een object georiënteerde wereld

Pattern matching

• Switch on steroids

1 match { case 1 => "one" case 2 => "two" } // "one"

(1, "one") match { case (2, string) => "first" case (1, string) => "second" case (_, "one") => "third" case (1, "one") => "fourth" case _ => "no match" }

Page 28: Scala: Functioneel programmeren in een object georiënteerde wereld

Pattern matchingsealed trait Job case object Sales extends Job case object Boss extends Job case class Programmer(lang: String) extends Job

case class Employee(name: String, job: Job)

val henry = Employee("Henry", Programmer("Scala")) val james = Employee("James", Boss) val peter = Employee("Peter", Sales)

henry.job match { case Boss => "bossing around" case Sales => "selling stuff" case Programmer(lang) => s"programming $lang" }

Page 29: Scala: Functioneel programmeren in een object georiënteerde wereld

null

new Garage().getCar(“Ferrari”) .navigationSystem() .routeTo("Berlin") .plan();

Page 30: Scala: Functioneel programmeren in een object georiënteerde wereld

null

RoutePlan plan = null; Car car = new Garage().getCar("Ferrari"); if (car != null) { NavSystem nav = ferrari.navSystem(); if (nav != null) { Route route = nav.routeTo("Berlin"); if (route != null) { plan = route.plan(); } } }

Page 31: Scala: Functioneel programmeren in een object georiënteerde wereld

Option

• Geeft aan dat iets optioneel is

• Trait

• Case classes: Some(x: Any), None

Page 32: Scala: Functioneel programmeren in een object georiënteerde wereld

null vs Optionval garage = new Garage()

val routePlan = for { //Car <- Option[Car] car <- garage.getCar("Ferrari")

//NavSystem <- Option[NavSystem] nav <- car.navigationSystem

//Route <- Option[Route] route <- nav.routeTo("Berlin")

//RoutePlan <- Option[RoutePlan] plan <- route.plan

//RoutePlan -> Option[RoutePlan] } yield plan

Page 33: Scala: Functioneel programmeren in een object georiënteerde wereld

null vs Option

val garage = new Garage()

val routePlan = for { car <- garage.getCar("Ferrari") nav <- car.navigationSystem route <- nav.routeTo("Berlin") plan <- route.plan } yield plan

Page 34: Scala: Functioneel programmeren in een object georiënteerde wereld

QuickSort

• Sorteeralgoritme

• O(n log n) performance

Page 35: Scala: Functioneel programmeren in een object georiënteerde wereld

QuickSort• Neem een lijst met getallen

• Neem een getal ‘x’ uit deze lijst

• Uit de rest van de lijst:

• Zet de getallen lager dan ‘x’ voor ‘x’ en sorteer

• Zet de getallen hoger dan ‘x’ na ‘x’ en sorteer

Page 36: Scala: Functioneel programmeren in een object georiënteerde wereld

QuickSort• Recursieve functie

• Base case: Lege lijst

• Andere cases: Niet-lege lijst

• Manier om lijst op te delen o.b.v. predikaat

• Hogere orde functies!

Page 37: Scala: Functioneel programmeren in een object georiënteerde wereld

QuickSort

• Lijst: [5, 3, 10, 7, 1]

• x: 5, rest: [3, 10, 7, 1]

• sort([3, 1]) 5 sort([10, 7])

Page 38: Scala: Functioneel programmeren in een object georiënteerde wereld

QuickSort

• [3, 1]

• x: 3, rest: [1]

• sort([1]) 3 sort([])

Page 39: Scala: Functioneel programmeren in een object georiënteerde wereld

QuickSort

• [1]

• x: 1, rest: []

• sort([]) 1 sort([])

• [] 1 []

• [1]

Page 40: Scala: Functioneel programmeren in een object georiënteerde wereld

QuickSort

• [3, 1]

• x: 3, rest: [1]

• sort([1]) 3 sort([])

• [1] 3 []

• [1, 3]

Page 41: Scala: Functioneel programmeren in een object georiënteerde wereld

QuickSort• Lijst: [5, 3, 10, 7, 1]

• x: 5, rest: [3, 10, 7, 1]

• sort([3, 1]) 5 sort([10, 7])

• [1, 3] 5 sort([10, 7])

• [1, 3] 5 [7, 10]

• [1, 3, 5, 7, 10]

Page 42: Scala: Functioneel programmeren in een object georiënteerde wereld

QuickSort

def qsort(ints: List[Int]): List[Int] = ints match { case Nil => Nil case head :: tail => { val (lower, higher) = tail partition { _ < head } qsort(lower) ++ (head :: qsort(higher)) } }

Page 43: Scala: Functioneel programmeren in een object georiënteerde wereld

QuickSort

def qsort(ints: List[Int]): List[Int] = ints match { case Nil => Nil case head :: tail => { val (lower, higher) = tail partition { _ < head } qsort(lower) ++ (head :: qsort(higher)) } }

Page 44: Scala: Functioneel programmeren in een object georiënteerde wereld

QuickSort

def qsort(ints: List[Int]): List[Int] = ints match { case Nil => Nil case head :: tail => { val (lower, higher) = tail partition { _ < head } qsort(lower) ++ (head :: qsort(higher)) } }

Page 45: Scala: Functioneel programmeren in een object georiënteerde wereld

QuickSort

def qsort(ints: List[Int]): List[Int] = ints match { case Nil => Nil case head :: tail => { val (lower, higher) = tail partition { _ < head } qsort(lower) ++ (head :: qsort(higher)) } }

Page 46: Scala: Functioneel programmeren in een object georiënteerde wereld

QuickSort

def qsort(ints: List[Int]): List[Int] = ints match { case Nil => Nil case head :: tail => { val (lower, higher) = tail partition { _ < head } qsort(lower) ++ (head :: qsort(higher)) } }

Page 47: Scala: Functioneel programmeren in een object georiënteerde wereld

QuickSort

def qsort(ints: List[Int]): List[Int] = ints match { case Nil => Nil case head :: tail => { val (lower, higher) = tail partition { _ < head } qsort(lower) ++ (head :: qsort(higher)) } }

Page 48: Scala: Functioneel programmeren in een object georiënteerde wereld

Vragen?