packages feed

open-union-0.2.0.0: open-union.cabal

name:               open-union
version:            0.2.0.0
synopsis:           Extensible, type-safe unions.
category:           Data
license:            MIT
license-file:       LICENSE
author:             Zeke Foppa
homepage:           https://github.com/bfopa/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 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.

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

    build-depends: base == 4.*
                 , type-fun

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

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