The overloaded-records package

[Tags:bsd3, library, test]

Implementation of Overloaded Record Fields based on current GHC proposal. It is built on top of functionality that is included in GHC 8.0.1, but it works on older GHC versions as well. Most importantly, this library provides Template Haskell functions for automatic deriving of instancess for HasField and ModifyField type classes. With these instances overloaded fields can be used directly as getters and lenses.

See README for usage examples.

More about the current status of OverloadedRecordFields language extension can be found on: GHC Wiki: OverloadedRecordFields.


[Skip to Readme]

Properties

Versions 0.1.0.0, 0.2.0.0, 0.3.0.0, 0.4.0.0, 0.4.1.0, 0.4.2.0 (info)
Change log ChangeLog.md
Dependencies base (>=4.7 && <5), data-default-class (>=0.0 && <0.2), template-haskell (>=2.9 && <2.12), transformers (==0.5.*) [details]
License BSD3
Copyright (c) 2016, Peter Trško
Author Peter Trško
Maintainer peter.trsko@gmail.com
Stability Unknown
Category Data
Home page https://github.com/trskop/overloaded-records
Bug tracker https://github.com/trskop/overloaded-records/issues
Source repository head: git clone git://github.com/trskop/overloaded-records.git
this: git clone git://github.com/trskop/overloaded-records.git(tag 0.4.2.0)
Uploaded Wed Aug 17 09:54:44 UTC 2016 by PeterTrsko
Updated Wed Aug 17 10:04:26 UTC 2016 by PeterTrsko to revision 1
Distributions LTSHaskell:0.4.2.0, NixOS:0.4.2.0, Stackage:0.4.2.0, Tumbleweed:0.4.2.0
Downloads 225 total (16 in the last 30 days)
Votes
1 []
Status Docs available [build log]
Last success reported on 2016-11-21 [all 1 reports]

Modules

[Index]

Flags

NameDescriptionDefaultType
pedanticPass additional warning flags to GHC.DisabledManual
force-functor-classesForce dependency on transformers ==0.5.* when compiled with GHC <8 to define Eq1, Ord1 and Show1 instances for Rec data type.DisabledAutomatic

Use -f <flag> to enable a flag, or -f -<flag> to disable that flag. More info

Downloads

Maintainer's Corner

For package maintainers and hackage trustees

Readme for overloaded-records

Readme for overloaded-records-0.4.2.0

Overloaded Records

Hackage Hackage Dependencies Haskell Programming Language BSD3 License

Build

Description

Implementation of Overloaded Record Fields based on current GHC proposal. It is built on top of functionality that is included in GHC 8.0.1, but it works on older GHC versions as well. Most importantly, this library provides Template Haskell functions for automatic deriving of instancess for HasField and ModifyField type classes. With these instances overloaded fields can be used directly as getters and lenses.

import Data.Default (Default(def))
import Data.OverloadedRecords.TH (overloadedRecord)

newtype Bar a = Bar {_bar :: a}

overloadedRecord def ''Bar

On GHC 8.0.1 it is possible to just write:

{-# LANGUAGE OverloadedLabels #-}

import Control.Lens ((+~))

add :: Int -> Bar Int -> Bar Int
add n = #bar +~ n

For older GHC versions there is a family of Template Haskell functions that will derive overloaded labels in form of standard haskell definitions:

import Control.Lens ((+~))
import Data.OverloadedLabels.TH (label)

label "bar"

add :: Int -> Bar Int -> Bar Int
add n = bar +~ n

More about the current status of OverloadedRecordFields language extension can be found on GHC Wiki: OverloadedRecordFields.

Usage Example

Following is a more complex usage example that demonstrates some of the possibilities of Overloaded Labels provided by this library.

-- Basic set of language extensions required when defining instances for
-- classes and type families from "Data.OverloadedRecords".
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}

-- Following language extensions are required by code like this:

{-# LANGUAGE ConstraintKinds #-}
    -- Codomain of type family 'R' is a 'Constraint' kind.

{-# LANGUAGE FlexibleContexts #-}
    -- Required in example when field type (second argument of ':::') is a
    -- specific type instead of a polymorphic type.

{-# LANGUAGE TypeOperators #-}
    -- Required due to usage of ':::' type alias.

-- Following language extensions are available only in GHC >=8:

{-# LANGUAGE OverloadedLabels #-}
    -- Enables #label syntactic sugar.

module Example
  where

import Data.Default (Default(def))
    -- Provided by one of these packages:
    --
    -- * data-default
    -- * data-default-extra

import Data.OverloadedRecords
import Data.OverloadedRecords.TH (overloadedRecord)


data V3 a = V3
    { v3x :: !a
    , v3y :: !a
    , v3z :: !a
    }
  deriving Show

-- Following line derives instances for various type classes and type
-- families that are provided by the overloaded-records library.
--
-- However with def (default settings) this is done only for fields that
-- start with type name, data constructor name, or underscore. Prefix is
-- stripped. In example "v3x" is transformed in to "x" and so would be
-- "_x".
overloadedRecord def ''V3

data V4 a = V4
    { v4x :: !a
    , v4y :: !a
    , v4z :: !a
    , v4t :: !a
    }
  deriving Show

overloadedRecord def ''V4

zeroV3
    :: (Num a, R '["x" ::: a, "y" ::: a, "z" ::: a] r)
    => r -> r
zeroV3 = set' #x 0 . set' #y 0 . set' #z 0

The following type signatures for zeroV3 are equivalent:

zeroV3
    :: (Num a, R '["x" ::: a, "y" ::: a, "z" ::: a] r)
    => r -> r
zeroV3
    ::  ( Num a
        , ModifyField' "x" r a
        , ModifyField' "y" r a
        , ModifyField' "z" r a
        )
    => r -> r

One of the biggest features of Overloaded Records is the possibility to define functions that do not depend on concrete data types, but on the "fields" they provide. In example function zeroV3 can be applied to anything that has fields "x", "y", and "z" that reference values of some Num type:

λ> zeroV3 (V3 1 1 1 :: V3 Int)
V3 {_x = 0, _y = 0, _z = 0}
λ> zeroV3 (V4 1 1 1 1 :: V4 Int)
V4 {_x = 0, _y = 0, _z = 0, _t = 1}

Function zeroV3 can be also defined using operators from lens library:

import Control.Lens ((.~), simple)

zeroV3
    :: (Num a, R '["x" ::: a, "y" ::: a, "z" ::: a] r)
    => r -> r
zeroV3 r = r
    & #x . simple .~ 0
    & #y . simple .~ 0
    & #z . simple .~ 0

License

The BSD 3-Clause License, see LICENSE file for details. This implementation is based on original prototype, which is under MIT License.

Contributions

Contributions, pull requests and bug reports are welcome! Please don't be afraid to contact author using GitHub or by e-mail.

Related Work

  • ruin is a DSL for working with record types that also leverages OverloadedLabels language extension.
  • vinyl provides extensible records for Haskell with lenses using modern GHC features.