Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

For an example of clashing:

  data Person = Person {
    id :: Int,
    name :: Text
  }

  data Account = Account {
    id :: Int, # Oh no! Name clash
    amount :: Int
  }
This is because `id` isn't really a "field," among other thing it's a generated function so that

  id :: Amount -> Int
  id (Amount actualId _) = actualId
This particular case is compounded by the fact that `id` is already the name of the identity function in Haskell's standard library (one reason why many projects that roll their own standard library rename `id` to `identity`).

For the partiality:

  data AllowedItems = Person { id :: Int, name :: Text} | JustANormalInteger Int

  name (JustANormalInteger 5) # Blows up at runtime
That is name has the type AllowedItems -> Text, even though JustANormalInteger 5 is also a member of AllowedItems

The workaround for clashing is to prefix your fields with your type name (luckily Haskell still has module namespaces so you don't need a globally unique name, just one unique for your module).

The workaround for partiality is to disallow a type with a record to be anything other than that record (e.g. disallow JustANormalInteger or require that Person {...} must first be an independent type before it can be used in AllowedItems).

The talk of lenses is a way to generalize the notion of field accessors and talk about the "path" generated by a series of field accessors in a first class way. E.g. you might imagine that in a standard OO language

  myClass.field0.subField0.subSubField0
could have a stand-alone concept of `field0.subField0.subsubField0` as a path through `myClass` that you could then use either to get a value (get(field0.subField0.subSubField0, myClass)) or set a value (set(field0.subField0.subSubField0, myClass, newValue)).

Moreover, if you can talk about the paths through a class in a first-class way, what's to say that this path must actually correspond to a true field in a class? It could just be anything "field-like." For example:

  lens = integer.lastDigit.leastSignificantBit
  set(345, lens, 0) // Yields 344
even though the individual digits of myInteger aren't actually generally truly fields in any OO language nor are the individual bits of a number.

Because you have now removed the need for true "fields," lenses are one strategy to get around the hackiness of fields in Haskell and in fact in many ways represent an advance in expressiveness over "true" fields (although they suffer from not really being integrated into the language in the way faux-fields are currently in Haskell).



Whoops... apparently I was reading bash while writing this comment. Comments in Haskell should be `--` not `#`.




Consider applying for YC's Fall 2026 batch! Applications are open till July 27.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: