scala lens: an introduction

Download Scala lens: An introduction

If you can't read please download the document

Upload: knoldus-software-llp

Post on 13-Apr-2017

1.800 views

Category:

Education


0 download

TRANSCRIPT

Introduction to Lenses in Scala

Shivansh SrivastavaSoftware ConsultantKnoldus Software LLP

Agenda

What are Lens?

Why Lens ?

Available Implementations.

Demo.

What are LENS ?

What is Lens ?

A Lens is an abstraction from functional programming which helps to deal with a problem of updating compleximmutable nested objects.

Let's start with an example.

case class Turtle( xcor: Double, ycor: Double, heading: Double)

If we want to mutate the value of the heading then.

In the Old Scala Days(2.7):

case class Turtle(...) { def right(...): Turtle = Turtle(xcor,ycor,heading + delta)}

Scala 2.8 comes to the rescue:

case class Turtle(...) { def right(...): Turtle = copy(heading = heading + delta)

so far,
so good!

but now...

This is where its needs gets arose.

When Nesting plays its part

Why Lenses ?

Updating mutable

case class Turtle(var ..., ...) { def forward(dist: Double): Unit = { position.x += dist * cos(...) position.y += dist * sin(...) } ...

Updating (Mutable)

updating
(immutable)

case class Turtle(...) { def forward(dist: Double): Turtle = copy(position = position.copy( x = position.x + dist * cos(...), y = position.y + dist * sin(...)))

Updating (Immutable)

it gets
worse

case class Turtle(...) { def forward(dist: Double): Turtle = this.copy(position = this.position.copy( x = this.position.x + dist * cos(this....), y = this.position.y + dist * sin(this....)))

OO Style:

FP style

case class Turtle(...) // no methods

def forward(turtle: Turtle, dist: Double): Turtle = turtle.copy(position = turtle.position.copy( x = turtle.position.x + dist * cos(turtle....), y = turtle.position.y + dist * sin(turtle....)))

FP Style:

worse
still

n levels deep

// imperativea.b.c.d.e += 1

// functionala.copy( b = a.b.copy( c = a.b.c.copy( d = a.b.c.d.copy( e = a.b.c.d.e + 1))))

What if we go N levels deep:

case class Program( ... breeds: ListMap[String, Breed] = ListMap(), linkBreeds: ListMap[String, Breed] =
ListMap(), ...)

Production Code:

Production Code:

// if we had lenses this wouldn't get so repetitious// - ST 7/15/12if (isLinkBreed) program.copy(linkBreeds = orderPreservingUpdate( program.linkBreeds, program.linkBreeds(breedName).copy( owns = newOwns)))else program.copy(breeds = orderPreservingUpdate( program.breeds, program.breeds(breedName).copy( owns = newOwns)))

https://github.com/NetLogo/NetLogo/blob/15700ba6bcab813c5be8b49b8fa00c2204883b08/
headless/src/main/org/nlogo/compiler/StructureParser.scala#L266-L276

We Can Fix it:

omit needless repetition!

avoid nested copy()

The need of the lens arises when there is too much nesting.

If we want to increase userRating in this model then we will have to write such a code:

And we have to write the code below to confirm all of the addresses in BillInfo.

If we want to increase userRating in this model then we will have to write such a code:

If we increase a level of nesting in our structures then we will considerably increase amount of a code like this. In such cases lens give a cleaner way to make changes in nested structures.

Using we can do it much simpler:

many web application want to increase application throughput, responsiveness

where one task can make progress without waiting for all others to complete

where more than one task can make progress at same time.
Concurrent program can be executed on single core machine via time slic

You may execute concurrent program in parallel

Overall you play with threads

Available Implementations

There are several implementations in scala:

scalaz.Lens

Quicklens

Sauron

Available Implementations

If we want to use scalaz.Lens at first we should define lens:

scalaz.Lens:

The first type parameter is needed to set in which class(MainClass) we will change value and the second type parameter defines the class(FieldClass) of the field which we will change with the lens.

We should also send two functions to lensu(...) method. The first function defines how to change MainClass using a new value. The second function is used to get value of the field which we want to change.

Quicklens:

Use of scalaz.Lens is quite difficult.It is quite hard and we will reduce amount of the code only if we have very complex nesting and implement enough lens to compose them.

Quicklens has support of chain modifications which can be helpful if you want to change several fields at the same time

It is also possible to create reusable lens as well asin scalaz.Lens

QuickLens:

QuickLens:

And the lens composition is also possible:

Sauron:

It is said on the main page of Sauron repo it has been inspired by quicklens but it has much simpler implementation and less number of features. And also has additional dependency on

"org.scalamacros" % "paradise" % "2.1.0-M5"

Sauron:

The example below shows how to define lens for changing different objects:

Sauron:

The example below shows hot to define lens for changing different objects:

Results:

scalaz.Lens - If you already have scalaz in a project and you are not bothered to write some code in order to define lens

Quicklens - Easy to use and powerful enough to deal with the described problem

Sauron - Very similar to Quicklens and has a less size but also has less functionality

Refrences:

www.koff.io

Slides by Seth Tisue in ScalaDays 2013

https://github.com/pathikrit/sauron

https://github.com/adamw/quicklens

Thanks..!!