packages feed

open-union-0.1.0: open-union.cabal

name:               open-union
version:            0.1.0
synopsis:           Extensible, type-safe unions.
category:           Data
license:            MIT
author:             Ben Foppa
homepage:           https://github.com/RobotGymnast/open-union
maintainer:         benjamin.foppa@gmail.com
build-type:         Simple
cabal-version:      >= 1.9.2
description:
    Extensible, type-safe unions. This package is very new and likely to change.
    .
    Basic usage example:
    .
    > {-# LANGUAGE TypeOperators #-}
    > {-# LANGUAGE ScopedTypeVariables #-}
    > 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.

library
    hs-source-dirs:   .
    ghc-options:      -Wall
    exposed-modules:
                  Data.OpenUnion
                  Data.OpenUnion.Internal

    build-depends : base == 4.*

executable example
    hs-source-dirs:   .
    main-is: example.hs
    ghc-options: -Wall -fllvm -O2
    build-depends : base == 4.*
                  , open-union

source-repository head
  type: git
  location: https://github.com/RobotGymnast/open-union.git