pa-label: Labels, and labelled tuples and enums (GHC >9.2)

This is a package candidate release! Here you can preview how this package release will appear once published to the main package index (which can be accomplished via the 'maintain' link below). Please note that once a package has been published to the main package index it cannot be undone! Please consult the package uploading documentation for more information.

[maintain] [Publish]

Warnings:


[Skip to Readme]

Properties

Versions 0.1.0.0, 0.1.0.0, 0.1.0.1, 0.1.1.0, 0.1.2.0
Change log CHANGELOG.md
Dependencies base (>=4.16.4.0 && <4.17) [details]
License BSD-3-Clause
Copyright 2023 Possehl Analytics GmbH
Author
Maintainer Philip Patsch <philip.patsch@possehl-analytics.com>
Category Data
Home page https://github.com/possehl-analytics/pa-hackage
Uploaded by Profpatsch at 2024-03-16T12:09:27Z

Modules

Downloads

Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees


Readme for pa-label-0.1.0.0

[back to package description]

pa-label

One-module library to provide nice anonymous labelled tuples and enums.

If you have a function:

doBlorb
  :: Text
  -> Text
  -> Bool
  -> Bool
  -> Bool
  -> IO Text
doBlorb username password read write insert = do …

what do you do? At call-site you don’t see the names of any of the types.

Before GHC 9.2, one strategy would have been to create a newtype for every single argument:

data Username = Username Text
data Password = Password Text
data Read = Read Bool
data Write = Write Bool
data Insert = Insert Bool

but that is very verbose and leaks into global scope!

Instead, do this:

doBlorb
  :: Label "username" Text
  -> Label "password" Text
  -> Label "read" Bool
  -> Label "write" Bool
  -> Label "insert" Bool
  -> IO (Label "blorb" Text)
doBlorb username password read write insert = do …

then it becomes clear to the call-site, what to do. In the function you can access the labels with record dots to get to the inner types, e.g. username.username, read.read.

Even better, you can bundle things into anonymous tuples:

doBlorb
  :: T2 "username" Text
        "password" Text
  -> T3 "read" Bool
        "write" Bool
        "insert" Bool
  -> IO (Label "blorb" Text)
doBlorb user permission = do …

and access inside the function like user.username or permission.read. So much nicer!

We provide tuples up to size 3, for anything bigger the you should really just create a normal record with data. The great thing is that no use-site has to be adjusted as long as you name the record fields the same and use record-dot syntax everywhere.

There’s some experimental support for anonymous enums (E2/E3), they are useful in some situations, but not as often as anonymous tuples in our experience.


Approaches like vinyl or superrecord are more general, but very hard to understand and lead to bad error messages.

We have found that in practice it is nicer to use the a lot less magical and slightly more verbose T2/T3 and switch to normal records once you reach 4 fields.