First release of derive-has-field. Derive HasField instances for records

We have been using OverloadedRecordDot at work and I really like it. Persistent has this feature where it will derive HasField instances for each of the field names. I.e.

  accountNumber String

Allows you to write bankAccount.accountNumber instead of bankAccount.bankAccountAccountNumber. I want this for all of my data types! Check out
derive-has-field: Derive HasField instances with Template Haskell and the source code GitHub - chiroptical/derive-has-field

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TemplateHaskell #-}

import DeriveHasField

data BankAccount =
    { bankAccountAccountNumber :: String

deriveHasFieldWith (dropPrefix "bankAccount") ''BankAccount

Hope you enjoy!


Have you considered dropping the prefixed fields and go the -XDuplicateRecordFields route (perhaps in combination with -XNoFieldSelectors?)

1 Like

Yes. IIRC, the issue here is related to record updates.

Honestly, I am excited for the day where this all “just works” and I don’t have to think about the downsides. For now, this is a solution one could choose.

1 Like

I’ve experienced that record update pain (GHC complains ambiguous field updates all the time).

Sometimes I resort to the import alias trick to avoid the ambiguities, sometimes to generic-lens.

The combination of lens, generic-lens, and DuplicateRecordFields works great for us.


After reading the docs for DuplicateRecordFields it seems that explicitly performing construction / deconstruction helps with updates, because

Uses of fields that are always unambiguous because they mention the constructor, including construction and pattern-matching, may freely use duplicated field names.

So, if we have

data Foo = Foo {
    aaa :: Int,
    bbb :: Bool

data Bar = Bar {
    aaa :: Int,
    bbb :: Bool

we can write (with a little help from RecordWildcards)

boo :: Foo -> Bar -> Bar
boo foo Bar {aaa,..} = Bar { aaa =, .. }

even if this would be ambiguous:

boo' :: Foo -> Bar -> Bar
boo' foo bar = bar { aaa = }

Not a perfect solution, but might come in handy in some cases.