After seeing this comment on reddit asking if lens solves the “overloading issue” with Haskell’s record systems, I thought I’d write up what I found here. By the way, The answer is yes, it can solve the problem with makeFields . The code for this blog post is available as a github gist.

Often, when making lenses I’ll use makeLenses . This is one of the simplest Template Haskell lens functions, and tries to make a named lens for each field in your record. If you try to avoid the clashing field names by doing something like this:

… you’ll end up with many different (and long) names for everything. That’s not nice.

Instead you can use makeFields . This will give you a typeclass for each field called (for example) HasOne.

If we’d used makeFields in our example above, both Foo and Bar would be instances of HasOne, we could refer to the fields using the name one , and everything would be just rosy. A more complete example is below. I’ve used 2D and 3D vectors ( Vec2 and Vec3 ) to demonstrate how we can create lenses named x , y , and z super-simply just using makeFields .

Here, makeFields uses some default rules to strip away the underscore and record type name to transform our field names ( _vec3X , vec2X ) into the lens name ( x ). These rules can be customised by using makeFieldsWith .

We can use ghci to examine the created typeclasses (using :t HasX at the GHCI prompt):

class HasX c_a24V e_a24W | c_a24V -> e_a24W where x :: Functor f => (e0 -> f e0) -> c0 -> f c0 -- Defined at Fields.hs:21:1 instance HasX Vec2 Double -- Defined at Fields.hs:21:1 instance HasX Vec3 Double -- Defined at Fields.hs:22:1

Aside from the strange type variable names, this is fairly simple: the HasX class has a single value, x , which is the Lens into our record. The type parameters to HasX are the record type, then the field type. That means we can write a normal Vec2 like this.

Note that the type could be written simply as v :: Vec2 . Our more complicated type signature is just intended to illustrate how the type parameters get ‘filled in’. The tilde ( ~ ) in a type signature denotes equality.

A more useful example, in which we want to write a function that zeroes out the x component of any vector, is below:

We can also make 2- and 3- tuples instances of HasX and HasY like this: