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

[ bsd3, data, library, possehl-analytics ] [ Propose Tags ]

Modules

[Index] [Quick Jump]

Downloads

Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees

Candidates

Versions [RSS] 0.1.0.0, 0.1.0.1, 0.1.1.0
Change log CHANGELOG.md
Dependencies base (<5) [details]
License BSD-3-Clause
Copyright 2023 Possehl Analytics GmbH
Author
Maintainer Philip Patsch <philip.patsch@possehl-analytics.com>
Category Data, Possehl-Analytics
Home page https://github.com/possehl-analytics/pa-hackage
Uploaded by Profpatsch at 2024-03-16T12:10:50Z
Distributions NixOS:0.1.1.0
Reverse Dependencies 1 direct, 0 indirect [details]
Downloads 99 total (10 in the last 30 days)
Rating (no votes yet) [estimated by Bayesian average]
Your Rating
  • λ
  • λ
  • λ
Status Docs available [build log]
Last success reported on 2024-03-16 [all 1 reports]

Readme for pa-label-0.1.1.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.