open-union: Extensible, type-safe unions.

[ data, library, mit, program ] [ Propose Tags ] [ Report a vulnerability ]

Extensible, type-safe unions. This package is very new and likely to change.

Basic usage example (language tags ommitted due to https://github.com/haskell/cabal/issues/774)

import Data.OpenUnion
type MyUnion = Union '[Char, Int, [()]]
showMyUnion :: MyUnion -> String
showMyUnion
    =  (\(c :: Char) -> "char: " ++ show c)
    @> (\(i :: Int) -> "int: " ++ show i)
    @> (\(l :: [()]) -> "list length: " ++ show (length l))
    @> (\(s :: String) -> "string: " ++ s)
    @> typesExhausted
main :: IO ()
main = do
    putStrLn $ showMyUnion $ liftUnion (4 :: Int)
    putStrLn $ showMyUnion $ liftUnion 'a'
    putStrLn $ showMyUnion $ liftUnion [(), ()]

which prints:

int: 4
char: 'a'
list length: 2

Casting to an unrelated type does not cause errors; In the above example,showMyUnion contains a String case despite MyUnion not containing String - superfluous cases are ignored, for the time being.

typesExhausted is NOT a catchall. It is a null case, and using it as a catchall (or forgetting to provide a certain case, for instance) will result in an error like:

example.hs:12:8:
    Couldn't match type ‘Int : ('[] :\ [Char])’ with ‘'[]’
    Expected type: Union ('[Int] :\ String) -> String
      Actual type: Union '[] -> String
    In the second argument of ‘(@>)’, namely ‘typesExhausted’
    In the second argument of ‘(@>)’, namely
      ‘(\ (s :: String) -> "string: " ++ s) @> typesExhausted’

The left-hand parts of the `: (think type-level (:)) are the cases that still need to be satisfied.

Trying to lift an incorrect type to a Union will cause an error resembling:

example.hs:20:30:
    No instance for (Data.OpenUnion.Internal.LiftToUnion '[] [Char])
      arising from a use of ‘liftUnion’
    In the second argument of ‘($)’, namely ‘liftUnion "asdf"’
    In the second argument of ‘($)’, namely
      ‘showMyUnion $ liftUnion "asdf"’
    In a stmt of a 'do' block:
      putStrLn $ showMyUnion $ liftUnion "asdf"

The original use case for this library was code like this (snipped from some record/playback logic):

type TrackStates = '[Stopped, Recording, Playing]

startRecording
  :: Union (TrackStates :\ Recording)
  -> ([Note], Union '[Recording])

The (:\\) type-level operator is for removal from a set, i.e. startRecording can be applied to a track in any state except the Recording state.

Downloads

Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees

Candidates

Versions [RSS] 0.1.0, 0.1.0.0, 0.1.0.1, 0.2.0.0, 0.3.0.0, 0.4.0.0 (info)
Dependencies base (>=4 && <5), open-union, type-fun [details]
License MIT
Author Zeke Foppa
Maintainer benjamin.foppa@gmail.com
Category Data
Home page https://github.com/bfops/open-union
Source repo head: git clone https://github.com/bfops/open-union.git
Uploaded by BenFoppa at 2018-04-20T01:08:10Z
Distributions NixOS:0.4.0.0
Reverse Dependencies 4 direct, 2 indirect [details]
Executables example
Downloads 4784 total (15 in the last 30 days)
Rating (no votes yet) [estimated by Bayesian average]
Your Rating
  • λ
  • λ
  • λ
Status Docs available [build log]
Last success reported on 2018-04-20 [all 1 reports]