# learning Scalaz: day 11

Hey there. There's an updated html5 book version, if you want.

Yesterday we looked at Reader monad as a way of abstracting configuration, and introduced monad transformers.

Today, let's look at lenses. It's a hot topic many people are talking, and looks like it has clear use case.

### Go turtle go

Seth Tisue (@SethTisue) gave a talk on shapeless lenses at Scalathon this year. I missed the talk, but I am going to borrow his example.

scala> case class Point(x: Double, y: Double) defined class Point scala> case class Color(r: Byte, g: Byte, b: Byte) defined class Color scala> case class Turtle( position: Point, heading: Double, color: Color) scala> Turtle(Point(2.0, 3.0), 0.0, Color(255.toByte, 255.toByte, 255.toByte)) res0: Turtle = Turtle(Point(2.0,3.0),0.0,Color(-1,-1,-1))

Now without breaking the immutability, we want to move the turtle forward.

scala> case class Turtle(position: Point, heading: Double, color: Color) { def forward(dist: Double): Turtle = copy(position = position.copy( x = position.x + dist * math.cos(heading), y = position.y + dist * math.sin(heading) )) } defined class Turtle scala> Turtle(Point(2.0, 3.0), 0.0, Color(255.toByte, 255.toByte, 255.toByte)) res10: Turtle = Turtle(Point(2.0,3.0),0.0,Color(-1,-1,-1)) scala> res10.forward(10) res11: Turtle = Turtle(Point(12.0,3.0),0.0,Color(-1,-1,-1))

To update the child data structure, we need to nest `copy`

call. To quote from Seth's example again:

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

The idea is to get rid of unnecessary `copy`

calls.

### Lens

Let's look at `Lens`

in Scalaz7:

type Lens[A, B] = LensT[Id, A, B] object Lens extends LensTFunctions with LensTInstances { def apply[A, B](r: A => Store[B, A]): Lens[A, B] = lens(r) }

`Lens`

is a type alias for `LensT[Id, A, B]`

like many other typeclasses.

### LensT

`LensT`

looks like this:

import StoreT._ import Id._ sealed trait LensT[F[+_], A, B] { def run(a: A): F[Store[B, A]] def apply(a: A): F[Store[B, A]] = run(a) ... } object LensT extends LensTFunctions with LensTInstances { def apply[F[+_], A, B](r: A => F[Store[B, A]]): LensT[F, A, B] = lensT(r) } trait LensTFunctions { import StoreT._ def lensT[F[+_], A, B](r: A => F[Store[B, A]]): LensT[F, A, B] = new LensT[F, A, B] { def run(a: A): F[Store[B, A]] = r(a) } def lensgT[F[+_], A, B](set: A => F[B => A], get: A => F[B])(implicit M: Bind[F]): LensT[F, A, B] = lensT(a => M(set(a), get(a))(Store(_, _))) def lensg[A, B](set: A => B => A, get: A => B): Lens[A, B] = lensgT[Id, A, B](set, get) def lensu[A, B](set: (A, B) => A, get: A => B): Lens[A, B] = lensg(set.curried, get) ... }

### Store

What's a `Store`

?

type Store[A, B] = StoreT[Id, A, B] // flipped type |-->[A, B] = Store[B, A] object Store { def apply[A, B](f: A => B, a: A): Store[A, B] = StoreT.store(a)(f) }

It looks like a wrapper for setter `A => B => A`

and getter `A => B`

.

### Using Lens

Let's define `turtlePosition`

and `pointX`

:

scala> val turtlePosition = Lens.lensu[Turtle, Point] ( (a, value) => a.copy(position = value), _.position ) turtlePosition: scalaz.Lens[Turtle,Point] = scalaz.LensTFunctions$$anon$5@421dc8c8 scala> val pointX = Lens.lensu[Point, Double] ( (a, value) => a.copy(x = value), _.x ) pointX: scalaz.Lens[Point,Double] = scalaz.LensTFunctions$$anon$5@30d31cf9

Next we can take advantage of a bunch of operators introduced in `Lens`

. Similar to monadic function composition we saw in `Kleisli`

, `LensT`

implements `compose`

(symbolic alias `<=<`

), and `andThen`

(symbolic alias `>=>`

). I personally think `>=>`

looks cool, so let's use that to define `turtleX`

:

scala> val turtleX = turtlePosition >=> pointX turtleX: scalaz.LensT[scalaz.Id.Id,Turtle,Double] = scalaz.LensTFunctions$$anon$5@11b35365

The type makes sense since it's going form `Turtle`

to `Double`

. Using `get`

method we can get the value:

scala> val t0 = Turtle(Point(2.0, 3.0), 0.0, Color(255.toByte, 255.toByte, 255.toByte)) t0: Turtle = Turtle(Point(2.0,3.0),0.0,Color(-1,-1,-1)) scala> turtleX.get(t0) res16: scalaz.Id.Id[Double] = 2.0

Success! Setting a new value using `set`

method should return a new `Turtle`

:

scala> turtleX.set(t0, 5.0) res17: scalaz.Id.Id[Turtle] = Turtle(Point(5.0,3.0),0.0,Color(-1,-1,-1))

This works too. What if I want to `get`

the value, apply it to some function, and `set`

using the result? `mod`

does exactly that:

scala> turtleX.mod(_ + 1.0, t0) res19: scalaz.Id.Id[Turtle] = Turtle(Point(3.0,3.0),0.0,Color(-1,-1,-1))

There's a symbolic variation to `mod`

that's curried called `=>=`

. This generates `Turtle => Turtle`

function:

scala> val incX = turtleX =>= {_ + 1.0} incX: Turtle => scalaz.Id.Id[Turtle] = <function1> scala> incX(t0) res26: scalaz.Id.Id[Turtle] = Turtle(Point(3.0,3.0),0.0,Color(-1,-1,-1))

We are now describing change of internal values upfront and passing in the actual value at the end. Does this remind you of something?

### Lens as a State monad

That sounds like a state transition to me. In fact `Lens`

and `State`

I think are good match since they are sort of emulating imperative programming on top of immutable data structure. Here's another way of writing `incX`

:

scala> val incX = for { x <- turtleX %= {_ + 1.0} } yield x incX: scalaz.StateT[scalaz.Id.Id,Turtle,Double] = scalaz.StateT$$anon$7@38e61ffa scala> incX(t0) res28: (Turtle, Double) = (Turtle(Point(3.0,3.0),0.0,Color(-1,-1,-1)),3.0)

`%=`

method takes a function `Double => Double`

and returns a `State`

monad that expresses the change.

Let's make `turtleHeading`

and `turtleY`

too:

scala> val turtleHeading = Lens.lensu[Turtle, Double] ( (a, value) => a.copy(heading = value), _.heading ) turtleHeading: scalaz.Lens[Turtle,Double] = scalaz.LensTFunctions$$anon$5@44fdec57 scala> val pointY = Lens.lensu[Point, Double] ( (a, value) => a.copy(y = value), _.y ) pointY: scalaz.Lens[Point,Double] = scalaz.LensTFunctions$$anon$5@ddede8c scala> val turtleY = turtlePosition >=> pointY

This is no fun because it feels boilerplatey. But, we can now move turtle forward! Instead of general `%=`

, Scalaz even provides sugars like `+=`

for `Numeric`

lenses. Here's what I mean:

scala> def forward(dist: Double) = for { heading <- turtleHeading x <- turtleX += dist * math.cos(heading) y <- turtleY += dist * math.sin(heading) } yield (x, y) forward: (dist: Double)scalaz.StateT[scalaz.Id.Id,Turtle,(Double, Double)] scala> forward(10.0)(t0) res31: (Turtle, (Double, Double)) = (Turtle(Point(12.0,3.0),0.0,Color(-1,-1,-1)),(12.0,3.0)) scala> forward(10.0) exec (t0) res32: scalaz.Id.Id[Turtle] = Turtle(Point(12.0,3.0),0.0,Color(-1,-1,-1))

Now we have implemented `forward`

function without using a single `copy(position = ...)`

. It's nice but we still needed some prep work to get here, so there is some tradeoff. `Lens`

defines a lot more methods, but the above should be a good starter. Let's see them all again:

sealed trait LensT[F[+_], A, B] { def get(a: A)(implicit F: Functor[F]): F[B] = F.map(run(a))(_.pos) def set(a: A, b: B)(implicit F: Functor[F]): F[A] = F.map(run(a))(_.put(b)) /** Modify the value viewed through the lens */ def mod(f: B => B, a: A)(implicit F: Functor[F]): F[A] = ... def =>=(f: B => B)(implicit F: Functor[F]): A => F[A] = mod(f, _) /** Modify the portion of the state viewed through the lens and return its new value. */ def %=(f: B => B)(implicit F: Functor[F]): StateT[F, A, B] = mods(f) /** Lenses can be composed */ def compose[C](that: LensT[F, C, A])(implicit F: Bind[F]): LensT[F, C, B] = ... /** alias for `compose` */ def <=<[C](that: LensT[F, C, A])(implicit F: Bind[F]): LensT[F, C, B] = compose(that) def andThen[C](that: LensT[F, B, C])(implicit F: Bind[F]): LensT[F, A, C] = that compose this /** alias for `andThen` */ def >=>[C](that: LensT[F, B, C])(implicit F: Bind[F]): LensT[F, A, C] = andThen(that) }

### Lens laws

Seth says:

lens laws are common sense

(0. if I get twice, I get the same answer)

1. if I get, then set it back, nothing changes.

2. if I set, then get, I get what I set.

3. if I set twice then get, I get the second thing I set.

He's right. These are common sense. Here how Scalaz expresses it in code:

trait LensLaw { def identity(a: A)(implicit A: Equal[A], ev: F[Store[B, A]] =:= Id[Store[B, A]]): Boolean = { val c = run(a) A.equal(c.put(c.pos), a) } def retention(a: A, b: B)(implicit B: Equal[B], ev: F[Store[B, A]] =:= Id[Store[B, A]]): Boolean = B.equal(run(run(a) put b).pos, b) def doubleSet(a: A, b1: B, b2: B)(implicit A: Equal[A], ev: F[Store[B, A]] =:= Id[Store[B, A]]) = { val r = run(a) A.equal(run(r put b1) put b2, r put b2) } }

By making arbitrary turtles we can check if our `turtleX`

is ok. We'll skip it, but make sure you don't define weird lens that break the law.

### Links

There's an article by Jordan West titled An Introduction to Lenses in Scalaz, which I kind of skimmed and looks like Scalaz 6.

There's a video by Edward Kmett's Lenses: A Functional Imperative presented at the Boston Area Scala Enthusiasts (BASE).

Finally, there's a compiler plugin by Gerolf Seitz that generates lenses: gseitz/Lensed. The project seems to be at experimental stage, but it does show the potential of macro or compiler generating lenses instead of hand-coding them.

We'll pick it up from here later.

- Login to post comments