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