Hmm, this seems like a lame way to declare accessor and mutator functions. You could imagine that this would get out of hand pretty quickly if our record had lots of fields:

getField8 (Record _ _ _ _ _ _ _ x _ _) = x

Everybody recognized that this introduced a ridiculous amount of boilerplate, so Haskell's language designers added some syntactic sugar to automatically derive accessor and mutator functions for complicated records:

... but this forces us to write the Haskell equivalent of ugly Java code:

Java : p.setX(p.getX() + 10)
Haskell: setX (getX p + 10) p

Because of these limitations, Haskell's record syntax crashes and burns on more complicated record hierarchies, becoming unmaintainable in a hurry.

Lenses

However, Haskell doesn't require language support for implementing properties! After all, a property consists of a getter and setter, so we can package them both up into a single data type, which we call a Lens instead of a property.

We are slightly improving on Java notationally, but still way behind C#. However, we're just getting started. First off, we can take advantage of Haskell's syntactic support for operators, which are just infix functions:

That looks better, but it still resembles a functional style, especially the setter. What we really want is something stateful, in the spirit of imperative programming. Fortunately for us, we can use the State monad to implement an imperative programming style:

-- stateful version of (^=)
(^:=) :: Lens a b -> b -> State a ()
p ^:= b = do
a State a b
access p = do
a
Now we can write all our favorite imperative functions using the above two primitives:

Fortunately for you, Edward Kmett already wrote all these functions for you and provides them in the data-lens package. The only difference is that he factored the Lens type into a more efficient and elegant form and some of the operators use different symbols.

Categories

So if all we could do was ape C# syntax I wouldn't be writing this blog post, so it's time to dig a little deeper.

Haskell's greatest strength stems from the fact that it derives all of its design patterns from mathematics, specifically category theory. Haskell borrows the Category design pattern from category theory, which is defined as anything that implements composition and identity:

class Category c where
(.) :: c y z -> c x y -> c x z
id :: c x x

Obviously functions form a Category:

instance Category (->) where
(f . g) x = f (g x)
id x = x

However, lenses form a Category, too!

instance Category Lens where
... -- exercise for the reader!

Any Category instance must satisfy three laws (know as the Category Laws):

Left Identity: id . f = f

Right Identity: f . id = f

Associativity: (f . g) . h = f . (g . h)

Other than that, anything goes, which is why categories appear in so many unexpected places. Since Lenses are categories we can compose them, which results in a new Lens which composes their their accessor and mutator functions. In other words:

The Category class enforces seamless composition because of the Category laws. For example, when we compose two lenses, we can't "uncompose" the result because it is absolutely indistinguishable from the equivalent hand-written lens. This is what "seamless" means: the "seam" between the two lenses completely vanishes when we compose them. The Category design pattern guarantees leak-proof abstraction.

Haskell's lenses behave like "first-class l-values": You can pass lenses as arguments to functions, modify them or compose them and despite all of this you can still assign to the resulting expression. You don't need to read a long language specification to know whether or not a certain expression qualifies as something assignable. If it's a Lens, it's assignable, period.

Haskell lenses are implemented using ordinary, pure functions. Haskell language designers never built Lens into the language, which means that if you disagree with its implementation, you can implement your own version! In fact, Hackage lists several lens packages, although fclabels and data-lens are in my opinion the two best implementations at the moment.

Lenses are easier to combine. You don't have to write a new getter and setter to combine two lenses. Just compose them and you're done. Use all that time you save to do whatever it is Haskell programmers do with all the free time they supposedly have.

Lenses still require boilerplate lens definitions, but many solutions exist to this problem. Most lens packages provide Template Haskell macros to automatically derive lenses for records. That means that the final idiomatic Haskell equivalent to the original C# code would be:

data Point = Point { _x :: Double, _y :: Double }
data Circle = Circle { _center :: Point, _radius :: Double }
$( makeLenses [''Point, ''Circle] ) --
Template Haskell is poorly thought out in my opinion, but there are some ideas to replace it with a much more powerful template system that can be statically checked. That makes a very interesting topic in its own right, which I'll visit in a later post.

As a suggestion, I would like to see a guide about how to actually use fclabels and/or data-lens, since the hackage:d packages have no "how to" material whatsoever (although your material here goes a long way). I could even help, if there's anything to help with. I do so like this concept about `Lens`:es. :)

Yes, Planet Haskell has also been rife with stuff pertaining to lenses as of late... I'm sure you've read http://comonad.com/reader/2012/mirrored-lenses/ already, and http://r6.ca/blog/20120623T104901Z.html

A very nice introduction to lenses, thank you! I sure as hell approve your slam on the record syntax. I can't wait for something to be at last done about it in the language specs. Btw do are there any news on when it's going to happen?

So I think that the general consensus is that the new `lens` package has the right type for lenses. The reason people really like the new lens type is:

a) You don't even have to import the package to define lensesb) It's very very elegant and "self-evident" (i.e. there is exactly one right way to implement it)c) It supports polymorphic updated) It supports write-only and read-only lenses

Point (a) is very important, because if we define the new record syntax to use lenses you don't want the language definition to dependent on a particular package's data type. The new formulation of a lens requires only `Functor`s, so it is very easy to define a language specification that can automatically derive lenses for an arbitrary data type, even one with multiple constructors.

However, although the new lens type is essentially nailed down at this point, people are still debating over what the standard library of lens operators should look like. Edward has done a lot of work with his `lens` package showing the full range of power of the new lenses, but it is a very large and unapproachable package and I think people are waiting for him to distill out a smaller Haskell98 core package with few dependencies before they add lenses to the language.