open-union: Extensible, type-safe unions.
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)
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 [(), ()]
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])
(:\\) type-level operator is for removal from a set, i.e.
startRecording can be applied to a track in any state except the
|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]|
|Source repo||head: git clone https://github.com/bfops/open-union.git|
|Uploaded||by BenFoppa at 2018-04-20T01:08:10Z|
|Reverse Dependencies||4 direct, 2 indirect [details]|
|Downloads||4405 total (18 in the last 30 days)|
|Rating||(no votes yet) [estimated by Bayesian average]|
|Status||Docs available [build log]
Last success reported on 2018-04-20 [all 1 reports]