roles alternatives and similar packages
Based on the "Data" category.
Alternatively, view roles alternatives based on common mentions on social networks and blogs.

semanticsource
Parsing, analyzing, and comparing source code across many languages 
lens
Lenses, Folds, and Traversals  Join us on web.libera.chat #haskelllens 
codebuilder
Packages for defining APIs, running them, generating client code and documentation. 
text
Haskell library for space and timeefficient operations over Unicode text. 
cassava
A CSV parsing and encoding library optimized for ease of use and high performance 
compendiumclient
Mu (μ) is a purely functional framework for building micro services. 
holmes
A reference library for constraintsolving with propagators and CDCL. 
resourcepool
A highperformance striped resource pooling implementation for Haskell 
primitive
This package provides various primitive memoryrelated operations. 
discrimination
Fast linear time sorting and discrimination for a large class of data types 
IORefCAS
A collection of different packages for CAS based data structures. 
dependentsum
Dependent sums and supporting typeclasses for comparing and displaying them 
reflection
Reifies arbitrary Haskell terms into types that can be reflected back into terms 
dependentmap
Dependentlytyped finite maps (partial dependent products) 
streaming
An optimized general monad transformer for streaming applications, with a simple prelude of functions 
orgmodeparse
Attoparsec parser combinators for parsing orgmode structured text! 
texticu
This package provides the Haskell Data.Text.ICU library, for performing complex manipulation of Unicode text. 
scientific
Arbitraryprecision floatingpoint numbers represented using scientific notation
Build timeseriesbased applications quickly and at scale.
Do you think we are missing an alternative of roles or a related project?
README
roles
Composable, classbased roles.
Table of contents
What is the cost of a newtype
?
The conventional wisdom is that Haskell's newtype
gives you a zerocost
abstractionwrapping and unwrapping of newtype
s are purely a compiletime
operation. Unfortunately, this is not quite the case:
 A zerocost abstraction... or is it?
newtype User = User String
 'name x' and 'x' will refer to the same inmemory entity at runtime...
name :: User > String
name (User x) = x
 ...but 'maybeName x' and 'x' will not be the same at runtime:
 a new value of type 'Maybe String' is allocated, despite being
 identical to the input!
maybeName :: Maybe User > Maybe String
maybeName = fmap name
See the POPL '11 paper Generative Type Abstraction and Typelevel Computation for a more
through investigation of the problem and a solution, and the ICFP '14 paper Safe Zerocost Coercions for Haskell for
implementation of the Coercible
typeclass in Haskell. Still more information can be found on the Haskell wiki.
Background
The magical Coercible
class
The solution described in the second paper was to introduce a typeclass Coercible a b
of the
form
class Coercible a b where
coerce :: a > b
There is something a bit magical about a typeclass like this, that requires bakedin
compiler support:
Consider a declaration newtype New = MkNew Old
. Within the module where New
is
defined, we should be able to freely coerce
between New
and Old
. But then again,
if MkNew
is not exported, then outside of the module we should not be able to
coerce
between New
and Old
. As a result, the Coercible
class must involve special
compiler magic to ensure that coerce
is only available in the appropriate modules.
Lifting coercions
Let's revisit the maybeName
issue. Ideally, we would like to rewrite the example
to make the coercions explicit, to guarantee zero runtime cost:
newtype User = User String
name :: User > String
name = coerce
 GHC knows that it can coerce 'User' to 'String', but
 how about 'Maybe User' to 'Maybe String'?
maybeName :: Maybe User > Maybe String
maybeName = coerce
For this to work, we would need instances of Coercible User String
(provided by
GHC compiler magic, since we're in the module where User
is defined) and
also Coercible a b => Coercible (Maybe a) (Maybe b)
.
You might expect GHC could implement a generic "coercion lifting" rule of the form
Coercible a b => Coercible (f a) (f b)
. Unfortunately this would be unsound
in the presence of type families:
newtype User = MkUser String
type family Fam
type instance Fam String = Int
type instance Fam User = Double
If GHC naively added the coercion lifting rule, then we would be able to
coerce from Double
to Int
by:
Coercible User String => Coercible (Fam User) (Fam String)  a.k.a. Coercible Double Int!
This is obviously no good.
Roles to the rescue
It seems that sometimes we can lift a Coercion a b
to a Coercion (f a) (f b)
(e.g. for Maybe
) and sometimes we cannot (e.g. for Fam
). To figure out when
a coercion a > b
can be lifted to a coercion f a > f b
, GHC infers a role
for the type parameter of f
. If f
can safely support coercionlifting, then
we say f
's type parameter has a representational role; otherwise, it has a
nominal role.
Happily, GHC will infer that Maybe
's type parameter is representational, while
Fam
's type parameter is nominal. This lets our definition maybeName = coerce
pass the compiler, while attempting to coerce an Int
to a Double
via
Fam
will fail.
The roles
library
What problem does this library solve?
Unfortunately, in GHC Haskell there is currently (circa late 2017) no way to write something like this:
coerceFirst :: (Coercible a b, Functor f) => [f a] > Maybe (f b)
coerceFirst [] = Nothing
coerceFirst (x:_) = Just (coerce x)
{ GHC says:
• Couldn't match representation of type ‘f a’ with that of ‘f b’
arising from a use of ‘coerce’
NB: We cannot know what roles the parameters to ‘f’ have;
we must assume that the role is nominal
}
GHC rightly refuses to lift the coercion from a
to b
into a coercion from
f a
to f b
: it does not have any assurance that the functor
f
uses its type parameter representationally.
In other words, this function needs to have a constraint Representational f
that
means something like "f
's type parameter has a representational
role."
This library simply provides the Representational
typeclass for a variety of
types in base
and containers
.
How can I use this library?
Since it is not made up of GHC pixiedust magic, Representational
needs a way to
convince GHC that the lifted coercion is allowed.
It does this via the lone function of the Representational
class:
class Representational f where
rep :: Coercion a b > Coercion (f a) (f b)
A value of type Coercion a b
is like a certificate that tells GHC "you are allowed
to coerce a
to b
". You cash the certificate in by using coerceWith
, yielding
an actual coercion from a
to b
. The rep
function simply converts a certificate
for coercing a
to b
into a certificate for coercing f a
into f b
.
We can now fix the example from the previous section:
coerceFirst :: (Coercible a b, Representational f, Functor f) => [f a] > Maybe (f b)
coerceFirst [] = Nothing
coerceFirst (x:_) = Just (coerceWith (rep Coercion) x)
 ~~~~~~~~~~~~~~~~~~~~~~~~~
 
 This means: (1) Get a certificate verifying that we can coerce `a` to `b`.
 This certificate is `Coercion`, and we got it by making use
 of the constraint `Coercible a b`.
 (2) Since `f` is `Representational`, we can use `rep` to upgrade
 the certificate to a certificate for coercion from `f a` to `f b`.
 (3) Use `coerceWith` to hand the certificate over to GHC, obtaining
 an actual coercion from `f a` to `f b` in return.
{ GHC says: sounds good to me! }
For another usage example, see the withRecMap
function from justifiedcontainers
,
and the corresponding test case. A Representational
constraint is used to ensure
that large maps are not duplicated in memory, despite undergoing a complex series
of newtype
related manipulations. An earlier version of withRecMap
worked by
fmap
ping newtype wrappers and unwrappers, which caused an accidental duplication
of the map.
History
This package is a fork of Edward Kmett's original roles 0.1
. It offers
fewer instances of Representational
, in exchange for a much smaller set
of dependencies. The instances that involve new
and eta
have been
removed, and instances for containers
have been added.