the good parts in scalaz

30
copyright 2013 Trainologic LTD Scalaz – The Good Parts

Upload: kobib9

Post on 26-May-2015

845 views

Category:

Technology


5 download

DESCRIPTION

By Shimi Bandiel from Trainologic for Scalapeno Israel 2013

TRANSCRIPT

Page 1: The good parts in scalaz

copyright 2013 Trainologic LTD

Scalaz – The Good Parts

Page 2: The good parts in scalaz

2 copyright 2013 Trainologic LTD

Scalaz – The Good Parts

• Scalaz is one of the famous/infamous libraries in Scala.

• In this session we are going to overview some parts of

it.

• But first of all, who are the intended audience?

Scalaz

2

Page 3: The good parts in scalaz

3 copyright 2013 Trainologic LTD

Scalaz – The Good Parts

• We assume a certain level of familiarity with Scala

syntax and core libraries.

• You should be comfort with the following declaration:

Know Your Scala

3

numbers.foldRight(List.empty[Int]) {_ :: _}

Page 4: The good parts in scalaz

4 copyright 2013 Trainologic LTD

Scalaz – The Good Parts

• If you are a seasoned Haskell programmer, you’ll find

that Scalaz resembles Haskell.

• We are going to look at some features of Scalaz without

discussing Category Theory.

• We will see some of the power of Scalaz without going

into the full definitions and laws of the concepts.

• All of these have their place, but we don’t have time for

it all.

• Let’s start with Type Classes…

Scalaz

4

Page 5: The good parts in scalaz

5 copyright 2013 Trainologic LTD

Scalaz – The Good Parts

• First of all let’s make it clear: There is no relationship

between Type Classes and OO classes or idioms!

• They arrive of course from Haskell

• A Type Class defines a set of operations that must be

available on types belonging to this Type Class.

• Type Classes are being used extensively in the core

libraries in Scala, in 3rd parties and in Scalaz.

Type-Classes

5

Page 6: The good parts in scalaz

6 copyright 2013 Trainologic LTD

Scalaz – The Good Parts

• The first example of a type class in Scalaz we’re going

to discuss is Equal.

• It provides a type safe equality check.

• In contrast to the built-in Scala’s “==“ method.

• E.g.:

Equal

6

import scalaz._ import Scalaz._ val i1 = 5 //> i1 : Int = 5 val i2 = 6 //> i2 : Int = 6 val s1 = "8" //> s1 : String = 8 i1 == i2 //> res0: Boolean = false i1 == s1 //> res1: Boolean = false i1 === i2 //> res2: Boolean = false // i1 === s1 does not compile

Page 7: The good parts in scalaz

7 copyright 2013 Trainologic LTD

Scalaz – The Good Parts

• Well, this looks like a simple implicit conversion that

provides the “===“ type-safe equality check.

• What is the connection to Type Classes here?

• Well, the way to create instances of type classes in

Scala, is to use implicits.

• And you can introduce your own implementations

whenever you want…

Discussion

7

Page 8: The good parts in scalaz

8 copyright 2013 Trainologic LTD

Scalaz – The Good Parts

• Consider the following code:

Discussion

8

// doesn’t compile here, no implicit Equal

new java.lang.Thread() === new java.lang.Thread()//

implicit object eqThread extends Equal[java.lang.Thread] {

def equal(a1: Thread, a2: Thread) = a1.getId === a2.getId

}

new java.lang.Thread() === new java.lang.Thread()//> res0: Boolean = false val t1 = new java.lang.Thread() //> t1 : Thread = Thread[Thread-2,5,main] t1 === t1 //> res1: Boolean = true

Page 9: The good parts in scalaz

9 copyright 2013 Trainologic LTD

Scalaz – The Good Parts

• The Order typeclass provides, well, ordering.

• E.g.:

Order

9

1 ?|? 2 //> res0: scalaz.Ordering = LT 1 ?|? 2.0 // does not compile

Page 10: The good parts in scalaz

1

0 copyright 2013 Trainologic LTD

Scalaz – The Good Parts

• Another useful Type Class is Show:

Show

10

1.show //> res0: scalaz.Cord = 1 "hello".show //> res1: scalaz.Cord = "hello“ // the following line doesn’t compile here

new Thread().show

implicit val showThread = Show.shows[Thread] { _.getName }

new Thread().show //> res2: scalaz.Cord = Thread-0

Page 11: The good parts in scalaz

1

1 copyright 2013 Trainologic LTD

Scalaz – The Good Parts

• No more printing “com.bom.mom.X@3249234f”

because we forgot to implement toString().

• It will not compile.

• You can also provide different printing for different

usecases (e.g., verbose mode, admin user, etc…).

Discussion

11

Page 12: The good parts in scalaz

1

2 copyright 2013 Trainologic LTD

Scalaz – The Good Parts

• We all favor using immutable data (and if not you

should).

• Especially if we’re into functional programming.

• However, this means that modification results in

creating a new ‘version’ of the object.

• This can be quite cumbersome.

• Let’s take a look at an example…

Lens

12

Page 13: The good parts in scalaz

1

3 copyright 2013 Trainologic LTD

Scalaz – The Good Parts

• Simple Lens usage:

Example

13

case class Customer(name: String, age: Int)

case class Stock(name: String, price: Int)

case class StockPortfolio(stocks: Map[String, Stock], customer: Customer)

val john = Customer("John", 30) //> john : lens.Customer = Customer(John,30) val customerAge = Lens.lensu[Customer, Int]((a, value) ⇒ a.copy(age = value), a ⇒ a.age)

val customerName = Lens.lensu[Customer, String]((a, value) ⇒ a.copy(name = value), a ⇒

a.name)

val jane = customerName set (john, "Jane")//> jane : lens.Customer = Customer(Jane,30) val johnNextYear = customerAge set (john, 31) //> johnNextYear : lens.Customer = Customer(John,31) val incCustomerAge = customerAge %= {_+1}

val johnNextYearAgain = incCustomerAge(john) //> johnNextYearAgain : (lens.Customer, Int) = (Customer(John,31),31)

Page 14: The good parts in scalaz

1

4 copyright 2013 Trainologic LTD

Scalaz – The Good Parts

• Composition:

Example

14

val sampleStock1 = Stock("Sample1", 500) val sampleStock2 = Stock("Sample2", 500)

val stockPrice = Lens.lensu[Stock, Int]((a, value) ⇒ a.copy(price = value), a ⇒ a.price)

val portfolioCustomer = Lens.lensu[StockPortfolio, Customer]((a, value) ⇒ a.copy(customer =

value), a ⇒ a.customer)

val portfolioStocks = Lens.lensu[StockPortfolio, Map[String, Stock]]((a, value) ⇒ a.copy(stocks

= value), a ⇒ a.stocks)

val portfolio = StockPortfolio(customer = john, stocks = Map("Sample1" -> sampleStock1,

"Sample2" -> sampleStock2))

portfolioStocks at "Sample1" andThen stockPrice set (portfolio, 9999)

//> res0: lens.StockPortfolio = StockPortfolio(Map(Sample1 -> Stock(Sample1,9999), Sample2 -> Stock(Sample2,500)),Customer(John,30))

Page 15: The good parts in scalaz

1

5 copyright 2013 Trainologic LTD

Scalaz – The Good Parts

• Scenario: we need to perform validation on some data.

• We want to accumulate the validations and not throw an

exception and break the flow.

• Scalaz provides the Validation class which can be used

for this purpose.

• Let’s see and discuss some examples…

Validation

15

Page 16: The good parts in scalaz

1

6 copyright 2013 Trainologic LTD

Scalaz – The Good Parts

• Validation:

Example

16

// Basic Data Types

case class Person(name: String, age: Int, yearsInSchool: Int, citizenship : Boolean)

// Validation Functions

trait PublicInstitue {

def checkEducation(p: Person): Validation[String, Person] = {

if (p.yearsInSchool < 12) "Not enough education".fail else p.success

}

def checkCitizenship(p : Person) : Validation[String, Person] = {

if (p.citizenship) p.success else "Must be a Citizen".fail

}

def checkAge(p : Person) : Validation[String, Person] = {

if (p.age < 18) "Too young".fail else if (p.age > 65) "Too old".fail else p.success

} }

Page 17: The good parts in scalaz

1

7 copyright 2013 Trainologic LTD

Scalaz – The Good Parts

• Ok, now let’s use the previous validation logic in a stop-

on-first-failure strategy:

First Usage

17

// let's try to get some persons a job at the Ministry of Wealth:

object MinistryOfHealth extends PublicInstitue {

def applyForJob(p : Person) : Validation[String, String] = {

for {

v1 <- checkEducation(p)

v2 <- checkCitizenship(p)

v3 <- checkAge(p)

} yield s"${v1.name}, you got the job"

}

}

// Failure(Must be a Citizen)

println( MinistryOfHealth applyForJob Person("John", 30, 15, citizenship = false))

// Success(Shraga, you got the job)

println( MinistryOfHealth applyForJob Person("Shraga", 30, 15, citizenship = true))

// Failure(Not enough education) println( MinistryOfHealth applyForJob Person("Dani", 13, 5, citizenship = true))

Page 18: The good parts in scalaz

1

8 copyright 2013 Trainologic LTD

Scalaz – The Good Parts

• OK, nice.

• Now lets accumulate the errors:

Accumulation

18

// let's try to get some persons a job at the Ministry of Transportation:

object MinistryOfTransportation extends PublicInstitue {

def applyForJob(p: Person) = {

(checkEducation(p) |@| checkCitizenship(p) |@| checkAge(p)) {

case (_, _, p) ⇒ s"${p.name}, you got the job"

}

}

}

println(MinistryOfTransportation applyForJob Person("John", 30, 15, citizenship = false))

println(MinistryOfTransportation applyForJob Person("Shraga", 30, 15, citizenship = true))

// Failure(Not enough educationToo young) println(MinistryOfTransportation applyForJob Person("Dani", 13, 5, citizenship = true))

Page 19: The good parts in scalaz

1

9 copyright 2013 Trainologic LTD

Scalaz – The Good Parts

• First of all, you can use the following line instead of the

|@| operator:

Discussion

19

(checkEducation(p) ⊛ checkCitizenship(p) ⊛ checkAge(p)) {

• Second, concatenating strings is not that useful.

• Let’s use a non empty list on the failure side:

def applyForJob(p: Person) = {

(checkEducation(p).toValidationNel ⊛ checkCitizenship(p).toValidationNel ⊛

checkAge(p).toValidationNel) {

}

// Failure(NonEmptyList(Not enough education, Too young))

println(MinistryOfTransportation applyForJob Person("Dani", 13, 5, citizenship = true))

Page 20: The good parts in scalaz

2

0 copyright 2013 Trainologic LTD

Scalaz – The Good Parts

• We have seen here the use for ApplicativeBuilder

operator: |@|

• Also known as the “macaulay culkin” operator

ApplicativeBuilder

20

Page 21: The good parts in scalaz

2

1 copyright 2013 Trainologic LTD

Scalaz – The Good Parts

• And, what if we have a long sequence of validation

methods?

• We wouldn’t want to type all of them. Right?

• We’re not going to discuss it here, but the following

code will do just fine:

What If?

21

def applyForJob(p: Person) = {

val validations = List(checkEducation _, checkCitizenship _, checkAge _)

validations.traverse[({type l[a] = ValidationNel[String, a]})#l, Person](_ andThen

(_.toValidationNel) apply p) map { case p::_ ⇒ s"${p.name}, you got the job" }

}

Page 22: The good parts in scalaz

2

2 copyright 2013 Trainologic LTD

Scalaz – The Good Parts

• Well, the Validation type is very useful compared to the

pre-defined Either type.

• Scalaz also provides the \/ type which is almost like

either, but supports for-comprehensions on the right

projection.

Discussion

22

Page 23: The good parts in scalaz

2

3 copyright 2013 Trainologic LTD

Scalaz – The Good Parts

• Well, combinators in Validation was nice.

• Also, for-comprehensions are nice.

• Functors, Applicatives and Monads are very useful.

• And they are depicted in Scalaz by appropriate Type

Classes.

• Let’s do a quick overview…

Discussion

23

Page 24: The good parts in scalaz

2

4 copyright 2013 Trainologic LTD

Scalaz – The Good Parts

• The Functor type class include types that can be

mapped on.

• Example:

Functor Type Class

24

def foo[F[_] : Functor](fs : F[Int]): F[Int] = {

fs map {_ + 5}

}

val numbers = List(1,2,3) //> numbers : List[Int] = List(1, 2, 3) foo(numbers) //> res0: List[Int] = List(6, 7, 8) val optInt = some(5) //> optInt : Option[Int] = Some(5) foo(optInt) //> res1: Option[Int] = Some(10)

Page 25: The good parts in scalaz

2

5 copyright 2013 Trainologic LTD

Scalaz – The Good Parts

• Applicatives were used in the validation examples.

• Let’s understand them more.

• E.g.:

Applicative

25

val opt1 = some(6) //> opt1 : Option[Int] = Some(6) val opt2 = some(7) //> opt2 : Option[Int] = Some(7)

(opt1).<*>(opt2.map(x => (y : Int) => x + y)) //> res0: Option[Int] = Some(13)

(opt1 |@| opt2) (_+_) //> res0: Option[Int] = Some(13)

Page 26: The good parts in scalaz

2

6 copyright 2013 Trainologic LTD

Scalaz – The Good Parts

• We can also lift simple values into the Applicative.

• E.g.:

Lifting into Applicative

26

(opt1 ⊛ opt2 ⊛ 6.point[Option]) (_+_ +_) //> res1: Option[Int] = Some(19)

Page 27: The good parts in scalaz

2

7 copyright 2013 Trainologic LTD

Scalaz – The Good Parts

• And there are of course, the famous Monads.

• Used in for-comprehensions.

• Instances: Option, Traversables, Validation, Reader,

Writer, State, IO and many more…

Monads

27

Page 28: The good parts in scalaz

2

8 copyright 2013 Trainologic LTD

Scalaz – The Good Parts

• Another nice type, is the Memo type that provides, well,

memoization.

• E.g.:

Memo

28

def delay = {

Thread.sleep(50)

1

}

val fac: Int => Int = {

case 1 => 1

case n => n*fac(n-1)*delay

}

val start = java.lang.System.currentTimeMillis

println(fac(50))

println(fac(10))

println(fac(50))

val end = java.lang.System.currentTimeMillis

println(s"${end-start} millis") // takes around 5000 millis

}

Page 29: The good parts in scalaz

2

9 copyright 2013 Trainologic LTD

Scalaz – The Good Parts

• And now, with memoization:

Memo

29

def delay = {

Thread.sleep(50)

1

}

val fac: Int => Int =Memo.mutableHashMapMemo {

case 1 => 1

case n => n*fac(n-1)*delay

}

val start = java.lang.System.currentTimeMillis

println(fac(50))

println(fac(10))

println(fac(50))

val end = java.lang.System.currentTimeMillis

println(s"${end-start} millis") // takes around 2500 millis

}

Page 30: The good parts in scalaz

3

0 copyright 2013 Trainologic LTD

Scalaz – The Good Parts

• There are several memoization strategies, including:

• weakHashMap

• Mutable/immutable maps

• Arrays

Memo

30