enum-subset-generate: Generate an ADT being a subset of another ADT, and the corresponding mappings.

[ bsd3, data, library ] [ Propose Tags ]


Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees


  • No Candidates
Versions [RSS],,,
Change log ChangeLog.md
Dependencies base (>=4.7 && <5), microlens, template-haskell [details]
License BSD-3-Clause
Copyright 2018 Georg Rudoy
Author Georg Rudoy
Maintainer 0xd34df00d@gmail.com
Category Data
Home page https://github.com/0xd34df00d/enum-subset-generate#readme
Bug tracker https://github.com/0xd34df00d/enum-subset-generate/issues
Source repo head: git clone https://github.com/0xd34df00d/enum-subset-generate
Uploaded by 0xd34df00d at 2024-01-22T05:56:19Z
Distributions LTSHaskell:, NixOS:, Stackage:
Reverse Dependencies 1 direct, 0 indirect [details]
Downloads 1291 total (21 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-01-22 [all 1 reports]

Readme for enum-subset-generate-

[back to package description]


Build Status

Generates an ADT having a subset of constructors of some other ADT along with a pair of functions to map between the two.


Consider implementing FFI bindings for a library. The lower level (directly mapping the C API onto Haskell) might expose an enumeration as an ADT, not all values of which might make sense for higher-level well-typed code. In this case the higher-level bindings might instead expose the generated ADT.

As an example, consider a parser library for a language like C++ or Java. A cursor pointing to a node in an AST might have a property like

enum AccessSpecifier {

AccessSpecifier getAccessSpecifier(Cursor*);

Access specifier doesn't make much sense for a node representing a for-loop, hence the AS_Invalid member.

A low-level Haskell bindings library might translate this enum into

module Library.Bindings.FFI where

-- ...

data AccessSpecifier = Invalid
                     | Public
                     | Protected
                     | Private
                     deriving (Eq, Ord, Show)

getAccessSpecifier :: Cursor -> BindingsMonad AccessSpecifier

A more type-safe wrapper around this might introduce typed cursors and add a constraint to the function:

module Library.Bindings.Pure where

import qualified Library.Bindings.FFI as FFI

accessSpecifier :: HasAccessSpecifier t => Cursor t -> FFI.AccessSpecifier

so this accessSpecifier is guaranteed to always produce a non-Invalid result. But since it's not explicitly stated in the types, the calling code will not be able to know about this, so the compiler's case analyzer might still require handling the case of Invalid.

Using this library, one might instead just do

-- Generate an AccessSpecifier in this module using FFI.AccessSpecifier
-- but without the FFI.Invalid constructor.
mkEnum ''FFI.AccessSpecifier ['FFI.Invalid]

accessSpecifier :: HasAccessSpecifier t => Cursor t -> AccessSpecifier