haskus-utils (empty) → 0.6.0.0
raw patch · 31 files changed
+5675/−0 lines, 31 filesdep +basedep +containersdep +extrasetup-changed
Dependencies added: base, containers, extra, file-embed, haskus-utils, list-t, mtl, stm, stm-containers, tasty, tasty-quickcheck, template-haskell, transformers, vector
Files
- LICENSE +27/−0
- Setup.hs +2/−0
- haskus-utils.cabal +83/−0
- src/lib/Haskus/Utils/ContFlow.hs +159/−0
- src/lib/Haskus/Utils/Embed.hs +14/−0
- src/lib/Haskus/Utils/Flow.hs +1775/−0
- src/lib/Haskus/Utils/HArray.hs +137/−0
- src/lib/Haskus/Utils/HList.hs +252/−0
- src/lib/Haskus/Utils/List.hs +14/−0
- src/lib/Haskus/Utils/Map.hs +6/−0
- src/lib/Haskus/Utils/Maybe.hs +27/−0
- src/lib/Haskus/Utils/Monad.hs +43/−0
- src/lib/Haskus/Utils/MultiState.hs +101/−0
- src/lib/Haskus/Utils/Parser.hs +189/−0
- src/lib/Haskus/Utils/STM.hs +61/−0
- src/lib/Haskus/Utils/STM/Future.hs +59/−0
- src/lib/Haskus/Utils/STM/TEq.hs +17/−0
- src/lib/Haskus/Utils/STM/TGraph.hs +85/−0
- src/lib/Haskus/Utils/STM/TList.hs +263/−0
- src/lib/Haskus/Utils/STM/TMap.hs +98/−0
- src/lib/Haskus/Utils/STM/TSet.hs +108/−0
- src/lib/Haskus/Utils/STM/TTree.hs +78/−0
- src/lib/Haskus/Utils/Tuple.hs +496/−0
- src/lib/Haskus/Utils/Types.hs +76/−0
- src/lib/Haskus/Utils/Types/Generics.hs +75/−0
- src/lib/Haskus/Utils/Types/List.hs +276/−0
- src/lib/Haskus/Utils/Variant.hs +932/−0
- src/tests/Haskus/Tests/Utils.hs +14/−0
- src/tests/Haskus/Tests/Utils/HArray.hs +92/−0
- src/tests/Haskus/Tests/Utils/Variant.hs +111/−0
- src/tests/Main.hs +5/−0
+ LICENSE view
@@ -0,0 +1,27 @@+Copyright (c) 2013-2017, Haskus organization+All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above copyright+ notice, this list of conditions and the following disclaimer in the+ documentation and/or other materials provided with the distribution.++ * Neither the name of Sylvain Henry nor the names of other contributors + may be used to endorse or promote products derived from this software + without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY DIRECT,+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ haskus-utils.cabal view
@@ -0,0 +1,83 @@+name: haskus-utils+version: 0.6.0.0+synopsis: Haskus utility modules+license: BSD3+license-file: LICENSE+author: Sylvain Henry+maintainer: sylvain@haskus.fr+homepage: http://www.haskus.org/system+copyright: Sylvain Henry 2017+category: System+build-type: Simple+cabal-version: >=1.20++description:+ Various utility modules used by Haskus packages.++source-repository head+ type: git+ location: git://github.com/haskus/haskus-utils.git++library+ exposed-modules:+ Haskus.Utils.ContFlow+ Haskus.Utils.Variant+ Haskus.Utils.Monad+ Haskus.Utils.Parser+ Haskus.Utils.HArray+ Haskus.Utils.Flow+ Haskus.Utils.MultiState+ Haskus.Utils.HList+ Haskus.Utils.Embed+ Haskus.Utils.List+ Haskus.Utils.Map+ Haskus.Utils.Maybe+ Haskus.Utils.Types+ Haskus.Utils.Types.List+ Haskus.Utils.Types.Generics+ Haskus.Utils.STM+ Haskus.Utils.STM.TEq+ Haskus.Utils.STM.TMap+ Haskus.Utils.STM.TSet+ Haskus.Utils.STM.TList+ Haskus.Utils.STM.TTree+ Haskus.Utils.STM.Future+ Haskus.Utils.STM.TGraph+ Haskus.Utils.Tuple++ other-modules:++ build-depends: + base >= 4.9 && < 4.10+ , containers >= 0.5+ , list-t >= 0.4+ , stm >= 2.4+ , stm-containers >= 0.2+ , vector >= 0.11+ , transformers >= 0.4+ , mtl >= 2.2+ , template-haskell >= 2.10+ , file-embed >= 0.0.10+ , extra >= 1.4++ build-tools: + ghc-options: -Wall+ default-language: Haskell2010+ hs-source-dirs: src/lib++test-suite tests+ type: exitcode-stdio-1.0+ main-is: Main.hs+ hs-source-dirs: src/tests+ ghc-options: -O2 -Wall -threaded+ default-language: Haskell2010+ other-modules:+ Haskus.Tests.Utils+ , Haskus.Tests.Utils.HArray+ , Haskus.Tests.Utils.Variant++ build-depends: + base+ , haskus-utils+ , tasty >= 0.11+ , tasty-quickcheck >= 0.8
+ src/lib/Haskus/Utils/ContFlow.hs view
@@ -0,0 +1,159 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FunctionalDependencies #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE ImplicitParams #-}+{-# LANGUAGE BangPatterns #-}++-- | Continuation based control-flow+module Haskus.Utils.ContFlow+ ( ContFlow (..)+ , (>::>)+ , (>:-:>)+ , (>:%:>)+ , fret+ , fretN+ , freturn+ , freturnN+ , frec+ , ContListToTuple+ , ContTupleToList+ , StripR+ , AddR+ -- * Control-flow+ , fIf+ , Then (..)+ , Else (..)+ )+where++import Haskus.Utils.Tuple+import Haskus.Utils.Types+import Haskus.Utils.Types.List++-- this define has to be defined in each module using ContFlow for now+#define fdo ContFlow $ \__cs -> let ?__cs = __cs in do++-- | A continuation based control-flow+newtype ContFlow (xs :: [*]) r = ContFlow (ContListToTuple xs r -> r)++-- | Convert a list of types into the actual data type representing the+-- continuations.+type family ContListToTuple (xs :: [*]) r where+ ContListToTuple xs r = ListToTuple (AddR xs r)++-- | Convert a tuple of continuations into a list of types+type family ContTupleToList t r :: [*] where+ ContTupleToList t r = StripR (TupleToList t) r++type family AddR f r where+ AddR '[] r = '[]+ AddR (x ': xs) r = (x -> r) ': AddR xs r++type family StripR f r where+ StripR '[] r = '[]+ StripR ((x -> r) ': xs) r = x ': StripR xs r+ StripR ((x -> w) ': xs) r =+ TypeError ( 'Text "Invalid continuation return type `"+ ':<>: 'ShowType w ':<>: 'Text "', expecting `"+ ':<>: 'ShowType r ':<>: 'Text "'")++-- | Bind a flow to a tuple of continuations+(>::>) :: ContFlow xs r -> ContListToTuple xs r -> r+{-# INLINE (>::>) #-}+(>::>) (ContFlow f) !cs = f cs++infixl 0 >::>++-- | Bind a flow to a 1-tuple of continuations+(>:-:>) :: ContFlow '[a] r -> (a -> r) -> r+{-# INLINE (>:-:>) #-}+(>:-:>) (ContFlow f) c = f (Single c)++infixl 0 >:-:>++-- | Bind a flow to a tuple of continuations and+-- reorder fields if necessary+(>:%:>) :: forall ts xs r.+ ( ReorderTuple ts (ContListToTuple xs r)+ ) => ContFlow xs r -> ts -> r+{-# INLINE (>:%:>) #-}+(>:%:>) (ContFlow f) !cs = f (tupleReorder cs)++infixl 0 >:%:>++-- | Call the type-indexed continuation from the tuple passed as first parameter+fret :: forall x r t n xs.+ ( ExtractTuple n t (x -> r)+ , xs ~ ContTupleToList t r+ , Member x xs+ , n ~ IndexOf x xs+ , KnownNat n+ , CheckNub xs+ ) => t -> (x -> r)+{-# INLINE fret #-}+fret = tupleN @n @t @(x -> r)++-- | Implicitly call the type-indexed continuation in the context+freturn :: forall x r t n xs.+ ( ExtractTuple n t (x -> r)+ , xs ~ ContTupleToList t r+ , Member x xs+ , n ~ IndexOf x xs+ , KnownNat n+ , CheckNub xs+ , ?__cs :: t+ ) => x -> r+{-# INLINE freturn #-}+freturn = fret ?__cs++-- | Call the indexed continuation from the tuple passed as first parameter+fretN :: forall n x r t xs.+ ( ExtractTuple n t (x -> r)+ , xs ~ ContTupleToList t r+ , x ~ Index n xs+ , KnownNat n+ ) => t -> (x -> r)+{-# INLINE fretN #-}+fretN = tupleN @n @t @(x -> r)+++-- | Implicitly call the type-indexed continuation in the context+freturnN :: forall n x r t xs.+ ( ExtractTuple n t (x -> r)+ , xs ~ ContTupleToList t r+ , x ~ Index n xs+ , KnownNat n+ , ?__cs :: t+ ) => x -> r+{-# INLINE freturnN #-}+freturnN = fretN @n ?__cs+++-- | Recursive call+frec :: forall r xs.+ ( ?__cs :: ContListToTuple xs r+ ) => ContFlow xs r -> r+frec f = f >::> ?__cs+++----------------------------------------+-- Control-flow++data Then = Then+data Else = Else++fIf :: Bool -> ContFlow '[Then,Else] r+{-# INLINE fIf #-}+fIf b = fdo+ case b of+ True -> freturn Then+ False -> freturn Else
+ src/lib/Haskus/Utils/Embed.hs view
@@ -0,0 +1,14 @@+-- | Embed data into the executable binary+module Haskus.Utils.Embed+ ( embedBytes+ , module Data.FileEmbed+ )+where++import Language.Haskell.TH+import Data.FileEmbed+import Data.Word++-- | Embed bytes in a C array, return an Addr#+embedBytes :: [Word8] -> Q Exp+embedBytes bs = return $ LitE (StringPrimL bs)
+ src/lib/Haskus/Utils/Flow.hs view
@@ -0,0 +1,1775 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE ExistentialQuantification #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE AllowAmbiguousTypes #-}++-- | First-class control-flow (based on Variant)+module Haskus.Utils.Flow+ ( Flow+ , IOV+ , MonadIO (..)+ , MonadInIO (..)+ -- * Flow utils+ , flowRes+ , flowSingle+ , flowSetN+ , flowSet+ , flowLift+ , flowToCont+ , flowTraverse+ , flowFor+ , flowTraverseFilter+ , flowForFilter+ , Liftable+ , Catchable+ , MaybeCatchable+ -- * Non-variant single operations+ , (|>)+ , (<|)+ , (||>)+ , (<||)+ -- * Monadic/applicative operators+ , when+ , unless+ , guard+ , void+ , forever+ , foldM+ , foldM_+ , forM+ , forM_+ , mapM+ , mapM_+ , sequence+ , replicateM+ , replicateM_+ , filterM+ , join+ , (<=<)+ , (>=>)+ -- * Named operators+ , flowMap+ , flowBind+ , flowBind'+ , flowMatch+ , flowMatchFail+ -- * First element operations+ , (.~.>)+ , (>.~.>)+ , (.~+>)+ , (>.~+>)+ , (.~^^>)+ , (>.~^^>)+ , (.~^>)+ , (>.~^>)+ , (.~$>)+ , (>.~$>)+ , (.~|>)+ , (>.~|>)+ , (.~=>)+ , (>.~=>)+ , (.~!>)+ , (>.~!>)+ , (.~!!>)+ , (>.~!!>)+ -- * First element, pure variant+ , (.-.>)+ , (>.-.>)+ , (<.-.)+ , (<.-.<)+ -- * Functor, applicative equivalents+ , (<$<)+ , (<*<)+ , (<|<)+ -- * First element, const variant+ , (.~~.>)+ , (>.~~.>)+ , (.~~+>)+ , (>.~~+>)+ , (.~~^^>)+ , (>.~~^^>)+ , (.~~^>)+ , (>.~~^>)+ , (.~~$>)+ , (>.~~$>)+ , (.~~|>)+ , (>.~~|>)+ , (.~~=>)+ , (>.~~=>)+ , (.~~!>)+ , (>.~~!>)+ -- * Tail operations+ , (..~.>)+ , (>..~.>)+ , (..-.>)+ , (>..-.>)+ , (..-..>)+ , (>..-..>)+ , (..~..>)+ , (>..~..>)+ , (..~^^>)+ , (>..~^^>)+ , (..~^>)+ , (>..~^>)+ , (..~=>)+ , (>..~=>)+ , (..~!>)+ , (>..~!>)+ , (..~!!>)+ , (>..~!!>)+ -- * Tail catch operations+ , (..%~^>)+ , (>..%~^>)+ , (..%~^^>)+ , (>..%~^^>)+ , (..%~$>)+ , (>..%~$>)+ , (..%~!!>)+ , (>..%~!!>)+ , (..%~!>)+ , (>..%~!>)+ , (..?~^>)+ , (>..?~^>)+ , (..?~^^>)+ , (>..?~^^>)+ , (..?~$>)+ , (>..?~$>)+ , (..?~!!>)+ , (>..?~!!>)+ , (..?~!>)+ , (>..?~!>)+ -- * Caught element operations+ , (%~.>)+ , (>%~.>)+ , (%~+>)+ , (>%~+>)+ , (%~^^>)+ , (>%~^^>)+ , (%~^>)+ , (>%~^>)+ , (%~$>)+ , (>%~$>)+ , (%~|>)+ , (>%~|>)+ , (%~=>)+ , (>%~=>)+ , (%~!>)+ , (>%~!>)+ , (%~!!>)+ , (>%~!!>)+ , (?~.>)+ , (>?~.>)+ , (?~+>)+ , (>?~+>)+ , (?~^^>)+ , (>?~^^>)+ , (?~^>)+ , (>?~^>)+ , (?~$>)+ , (>?~$>)+ , (?~|>)+ , (>?~|>)+ , (?~=>)+ , (>?~=>)+ , (?~!>)+ , (>?~!>)+ , (?~!!>)+ , (>?~!!>)+ -- * Helpers+ , makeFlowOp+ , makeFlowOpM+ , selectTail+ , selectFirst+ , selectType+ , applyConst+ , applyPure+ , applyM+ , applyF+ , combineFirst+ , combineSameTail+ , combineEither+ , combineConcat+ , combineUnion+ , combineLiftUnselected+ , combineLiftBoth+ , combineSingle+ , liftV+ , liftF+ )+where++import Haskus.Utils.Variant+import Haskus.Utils.Types+import Haskus.Utils.Types.List+import Haskus.Utils.Monad+import Haskus.Utils.ContFlow++-- | Control-flow+type Flow m (l :: [*]) = m (Variant l)++type IOV l = Flow IO l++----------------------------------------------------------+-- Flow utils+----------------------------------------------------------++-- | Return in the first element+flowSetN :: forall (n :: Nat) xs m.+ ( Monad m+ , KnownNat n+ ) => Index n xs -> Flow m xs+{-# INLINE flowSetN #-}+flowSetN = return . setVariantN @n++-- | Return in the first well-typed element+flowSet :: (Member x xs, Monad m) => x -> Flow m xs+{-# INLINE flowSet #-}+flowSet = return . setVariant++-- | Return a single element+flowSingle :: Monad m => x -> Flow m '[x]+{-# INLINE flowSingle #-}+flowSingle = flowSetN @0++-- | Lift a flow into another+flowLift :: (Liftable xs ys , Monad m) => Flow m xs -> Flow m ys+{-# INLINE flowLift #-}+flowLift = fmap liftVariant++-- | Lift a flow into a ContFlow+flowToCont :: (ContVariant xs, Monad m) => Flow m xs -> ContFlow xs (m r)+flowToCont = variantToContM++-- | Traverse a list and stop on first error+flowTraverse :: forall m a b xs.+ ( Monad m+ ) => (a -> Flow m (b ': xs)) -> [a] -> Flow m ([b] ': xs)+flowTraverse f = go (flowSetN @0 [])+ where+ go :: Flow m ([b] ': xs) -> [a] -> Flow m ([b] ': xs)+ go rs [] = rs >.-.> reverse+ go rs (a:as) = go rs' as+ where+ -- execute (f a) if previous execution succedded.+ -- prepend the result to the list+ rs' = rs >.~$> \bs -> (f a >.-.> (:bs))++-- | Traverse a list and stop on first error+flowFor :: forall m a b xs.+ ( Monad m+ ) => [a] -> (a -> Flow m (b ': xs)) -> Flow m ([b] ': xs)+flowFor = flip flowTraverse++-- | Traverse a list and return only valid values+flowTraverseFilter :: forall m a b xs.+ ( Monad m+ ) => (a -> Flow m (b ': xs)) -> [a] -> m [b]+flowTraverseFilter f = go+ where+ go :: [a] -> m [b]+ go [] = return []+ go (a:as) = do+ f a >.~.> (\b -> (b:) <$> go as)+ >..~.> const (go as)++-- | Traverse a list and return only valid values+flowForFilter :: forall m a b xs.+ ( Monad m+ ) => [a] -> (a -> Flow m (b ': xs)) -> m [b]+flowForFilter = flip flowTraverseFilter+++-- | Extract single flow result+flowRes :: Functor m => Flow m '[x] -> m x+{-# INLINE flowRes #-}+flowRes = fmap singleVariant+++-- | Lift an operation on a Variant into an operation on a flow+liftm :: Monad m => (Variant x -> a -> m b) -> Flow m x -> a -> m b+{-# INLINE liftm #-}+liftm op x a = do+ x' <- x+ op x' a++----------------------------------------------------------+-- Single element not wrapped into a variant+----------------------------------------------------------++-- | Apply a function+(|>) :: a -> (a -> b) -> b+{-# INLINE (|>) #-}+x |> f = f x++infixl 0 |>++-- | Apply a function+(<|) :: (a -> b) -> a -> b+{-# INLINE (<|) #-}+f <| x = f x++infixr 0 <|++-- | Apply a function in a Functor+(||>) :: Functor f => f a -> (a -> b) -> f b+{-# INLINE (||>) #-}+x ||> f = fmap f x++infixl 0 ||>++-- | Apply a function in a Functor+(<||) :: Functor f => (a -> b) -> f a -> f b+{-# INLINE (<||) #-}+f <|| x = fmap f x++infixr 0 <||++----------------------------------------------------------+-- Named operators+----------------------------------------------------------++-- | Map a pure function onto the correct value in the flow+flowMap :: Monad m => Flow m (x ': xs) -> (x -> y) -> Flow m (y ': xs)+{-# INLINE flowMap #-}+flowMap = (>.-.>)++-- | Bind two flows in a monadish way (error types union)+flowBind :: forall xs ys zs m x.+ ( Liftable xs zs+ , Liftable ys zs+ , zs ~ Union xs ys+ , Monad m+ ) => Flow m (x ': ys) -> (x -> Flow m xs) -> Flow m zs+{-# INLINE flowBind #-}+flowBind = (>.~|>)++-- | Bind two flows in a monadic way (constant error types)+flowBind' :: Monad m => Flow m (x ': xs) -> (x -> Flow m (y ': xs)) -> Flow m (y ': xs)+{-# INLINE flowBind' #-}+flowBind' = (>.~$>)++-- | Match a value in a flow+flowMatch :: forall x xs zs m.+ ( Monad m+ , Catchable x xs+ , Liftable (Filter x xs) zs+ ) => Flow m xs -> (x -> Flow m zs) -> Flow m zs+{-# INLINE flowMatch #-}+flowMatch = (>%~^>)++-- | Match a value in a flow and use a non-returning failure in this case+flowMatchFail :: forall x xs m.+ ( Monad m+ , Catchable x xs+ ) => Flow m xs -> (x -> m ()) -> Flow m (Filter x xs)+{-# INLINE flowMatchFail #-}+flowMatchFail = (>%~!!>)++----------------------------------------------------------+-- First element operations+----------------------------------------------------------++-- | Extract the first value, set the first value+(.~.>) :: forall m l x a.+ ( Monad m )+ => Variant (a ': l) -> (a -> m x) -> Flow m (x ': l)+{-# INLINE (.~.>) #-}+(.~.>) v f = makeFlowOp selectFirst (applyM f) combineFirst v++infixl 0 .~.>++-- | Extract the first value, set the first value+(>.~.>) :: forall m l x a.+ ( Monad m )+ => Flow m (a ': l) -> (a -> m x) -> Flow m (x ': l)+{-# INLINE (>.~.>) #-}+(>.~.>) = liftm (.~.>)++infixl 0 >.~.>++-- | Extract the first value, concat the result+(.~+>) :: forall (k :: Nat) m l l2 a.+ ( KnownNat k+ , k ~ Length l2+ , Monad m )+ => Variant (a ': l) -> (a -> Flow m l2) -> Flow m (Concat l2 l)+{-# INLINE (.~+>) #-}+(.~+>) v f = makeFlowOp selectFirst (applyF f) combineConcat v++infixl 0 .~+>++-- | Extract the first value, concat the results+(>.~+>) :: forall (k :: Nat) m l l2 a.+ ( KnownNat k+ , k ~ Length l2+ , Monad m )+ => Flow m (a ': l) -> (a -> Flow m l2) -> Flow m (Concat l2 l)+{-# INLINE (>.~+>) #-}+(>.~+>) = liftm (.~+>)++infixl 0 >.~+>++-- | Extract the first value, lift both+(.~^^>) :: forall m a xs ys zs.+ ( Monad m+ , Liftable xs zs+ , Liftable ys zs+ ) => Variant (a ': ys) -> (a -> Flow m xs) -> Flow m zs+{-# INLINE (.~^^>) #-}+(.~^^>) v f = makeFlowOp selectFirst (applyF f) combineLiftBoth v++infixl 0 .~^^>+++-- | Extract the first value, lift both+(>.~^^>) :: forall m a xs ys zs.+ ( Monad m+ , Liftable xs zs+ , Liftable ys zs+ ) => Flow m (a ': ys) -> (a -> Flow m xs) -> Flow m zs+{-# INLINE (>.~^^>) #-}+(>.~^^>) = liftm (.~^^>)++infixl 0 >.~^^>++-- | Extract the first value, lift unselected+(.~^>) :: forall m a ys zs.+ ( Monad m+ , Liftable ys zs+ ) => Variant (a ': ys) -> (a -> Flow m zs) -> Flow m zs+{-# INLINE (.~^>) #-}+(.~^>) v f = makeFlowOp selectFirst (applyF f) combineLiftUnselected v++infixl 0 .~^>++-- | Extract the first value, lift unselected+(>.~^>) :: forall m a ys zs.+ ( Monad m+ , Liftable ys zs+ ) => Flow m (a ': ys) -> (a -> Flow m zs) -> Flow m zs+{-# INLINE (>.~^>) #-}+(>.~^>) = liftm (.~^>)++infixl 0 >.~^>++-- | Extract the first value, use the same tail+(.~$>) :: forall m x xs a.+ ( Monad m+ ) => Variant (a ': xs) -> (a -> Flow m (x ': xs)) -> Flow m (x ': xs)+{-# INLINE (.~$>) #-}+(.~$>) v f = makeFlowOp selectFirst (applyF f) combineSameTail v++infixl 0 .~$>++-- | Extract the first value, use the same tail+(>.~$>) :: forall m x xs a.+ ( Monad m+ ) => Flow m (a ': xs) -> (a -> Flow m (x ': xs)) -> Flow m (x ': xs)+{-# INLINE (>.~$>) #-}+(>.~$>) = liftm (.~$>)++infixl 0 >.~$>++-- | Take the first output, union the result+(.~|>) ::+ ( Liftable xs zs+ , Liftable ys zs+ , zs ~ Union xs ys+ , Monad m+ ) => Variant (a ': ys) -> (a -> Flow m xs) -> Flow m zs+{-# INLINE (.~|>) #-}+(.~|>) v f = makeFlowOp selectFirst (applyF f) combineUnion v++infixl 0 .~|>++-- | Take the first output, fusion the result+(>.~|>) ::+ ( Liftable xs zs+ , Liftable ys zs+ , zs ~ Union xs ys+ , Monad m+ ) => Flow m (a ': ys) -> (a -> Flow m xs) -> Flow m zs+{-# INLINE (>.~|>) #-}+(>.~|>) = liftm (.~|>)++infixl 0 >.~|>++-- | Extract the first value and perform effect. Passthrough the input value+(.~=>) ::+ ( Monad m+ ) => Variant (a ': l) -> (a -> m ()) -> Flow m (a ': l)+{-# INLINE (.~=>) #-}+(.~=>) v f = case headVariant v of+ Right u -> f u >> return v+ Left _ -> return v++infixl 0 .~=>++-- | Extract the first value and perform effect. Passthrough the input value+(>.~=>) ::+ ( Monad m+ ) => Flow m (a ': l) -> (a -> m ()) -> Flow m (a ': l)+{-# INLINE (>.~=>) #-}+(>.~=>) = liftm (.~=>)++infixl 0 >.~=>++-- | Extract the first value and perform effect.+(.~!>) ::+ ( Monad m+ ) => Variant (a ': l) -> (a -> m ()) -> m ()+{-# INLINE (.~!>) #-}+(.~!>) v f = case headVariant v of+ Right u -> f u+ Left _ -> return ()++infixl 0 .~!>++-- | Extract the first value and perform effect.+(>.~!>) ::+ ( Monad m+ ) => Flow m (a ': l) -> (a -> m ()) -> m ()+{-# INLINE (>.~!>) #-}+(>.~!>) = liftm (.~!>)++infixl 0 >.~!>++-- | Extract the first value and perform effect.+(.~!!>) ::+ ( Monad m+ ) => Variant (a ': l) -> (a -> m ()) -> m (Variant l)+{-# INLINE (.~!!>) #-}+(.~!!>) v f = case headVariant v of+ Right u -> f u >> error ".~!!> error"+ Left l -> return l++infixl 0 .~!!>++-- | Extract the first value and perform effect.+(>.~!!>) ::+ ( Monad m+ ) => Flow m (a ': l) -> (a -> m ()) -> m (Variant l)+{-# INLINE (>.~!!>) #-}+(>.~!!>) = liftm (.~!!>)++infixl 0 >.~!!>++----------------------------------------------------------+-- First element, pure variant+----------------------------------------------------------++-- | Extract the first value, set the first value+(.-.>) :: forall m l x a.+ ( Monad m )+ => Variant (a ': l) -> (a -> x) -> Flow m (x ': l)+{-# INLINE (.-.>) #-}+(.-.>) v f = makeFlowOp selectFirst (applyPure (liftV f)) combineFirst v++infixl 0 .-.>++-- | Extract the first value, set the first value+(>.-.>) :: forall m l x a.+ ( Monad m )+ => Flow m (a ': l) -> (a -> x) -> Flow m (x ': l)+{-# INLINE (>.-.>) #-}+(>.-.>) = liftm (.-.>)++infixl 0 >.-.>++-- | Extract the first value, set the first value+(<.-.) :: forall m l x a.+ ( Monad m )+ => (a -> x) -> Variant (a ': l) -> Flow m (x ': l)+{-# INLINE (<.-.) #-}+(<.-.) = flip (.-.>)++infixr 0 <.-.++-- | Extract the first value, set the first value+(<.-.<) :: forall m l x a.+ ( Monad m )+ => (a -> x) -> Flow m (a ': l) -> Flow m (x ': l)+{-# INLINE (<.-.<) #-}+(<.-.<) = flip (>.-.>)++infixr 0 <.-.<++----------------------------------------------------------+-- Functor, applicative+----------------------------------------------------------++-- | Functor <$> equivalent+(<$<) :: forall m l a b.+ ( Monad m )+ => (a -> b) -> Flow m (a ': l) -> Flow m (b ': l)+{-# INLINE (<$<) #-}+(<$<) = (<.-.<)++infixl 4 <$<++-- | Applicative <*> equivalent+(<*<) :: forall m l a b.+ ( Monad m )+ => Flow m ((a -> b) ': l) -> Flow m (a ': l) -> Flow m (b ': l)+{-# INLINE (<*<) #-}+(<*<) mf mg = mf >.~$> (mg >.-.>)++infixl 4 <*<++-- | Applicative <*> equivalent, with error union+(<|<) :: forall m xs ys zs y z.+ ( Monad m+ , Liftable xs zs+ , Liftable ys zs+ , zs ~ Union xs ys+ ) => Flow m ((y -> z) ': xs) -> Flow m (y ': ys) -> Flow m (z ': zs)+{-# INLINE (<|<) #-}+(<|<) mf mg = + mf >..-..> liftVariant+ >.~$> (\f -> mg >..-..> liftVariant+ >.-.> f+ )++infixl 4 <|<++----------------------------------------------------------+-- First element, const variant+----------------------------------------------------------++-- | Extract the first value, set the first value+(.~~.>) :: forall m l x a.+ ( Monad m )+ => Variant (a ': l) -> m x -> Flow m (x ': l)+{-# INLINE (.~~.>) #-}+(.~~.>) v f = v .~.> const f++infixl 0 .~~.>++-- | Extract the first value, set the first value+(>.~~.>) :: forall m l x a.+ ( Monad m )+ => Flow m (a ': l) -> m x -> Flow m (x ': l)+{-# INLINE (>.~~.>) #-}+(>.~~.>) = liftm (.~~.>)++infixl 0 >.~~.>++-- | Extract the first value, concat the result+(.~~+>) :: forall (k :: Nat) m l l2 a.+ ( KnownNat k+ , k ~ Length l2+ , Monad m )+ => Variant (a ': l) -> Flow m l2 -> Flow m (Concat l2 l)+{-# INLINE (.~~+>) #-}+(.~~+>) v f = v .~+> const f++infixl 0 .~~+>++-- | Extract the first value, concat the results+(>.~~+>) :: forall (k :: Nat) m l l2 a.+ ( KnownNat k+ , k ~ Length l2+ , Monad m )+ => Flow m (a ': l) -> Flow m l2 -> Flow m (Concat l2 l)+{-# INLINE (>.~~+>) #-}+(>.~~+>) = liftm (.~~+>)++infixl 0 >.~~+>++-- | Extract the first value, lift the result+(.~~^^>) :: forall m a xs ys zs.+ ( Monad m+ , Liftable xs zs+ , Liftable ys zs+ ) => Variant (a ': ys) -> Flow m xs -> Flow m zs+{-# INLINE (.~~^^>) #-}+(.~~^^>) v f = v .~^^> const f++infixl 0 .~~^^>+++-- | Extract the first value, lift the result+(>.~~^^>) :: forall m a xs ys zs.+ ( Monad m+ , Liftable xs zs+ , Liftable ys zs+ ) => Flow m (a ': ys) -> Flow m xs -> Flow m zs+{-# INLINE (>.~~^^>) #-}+(>.~~^^>) = liftm (.~~^^>)++infixl 0 >.~~^^>++-- | Extract the first value, connect to the expected output+(.~~^>) :: forall m a ys zs.+ ( Monad m+ , Liftable ys zs+ ) => Variant (a ': ys) -> Flow m zs -> Flow m zs+{-# INLINE (.~~^>) #-}+(.~~^>) v f = v .~^> const f++infixl 0 .~~^>++-- | Extract the first value, connect to the expected output+(>.~~^>) :: forall m a ys zs.+ ( Monad m+ , Liftable ys zs+ ) => Flow m (a ': ys) -> Flow m zs -> Flow m zs+{-# INLINE (>.~~^>) #-}+(>.~~^>) = liftm (.~~^>)++infixl 0 >.~~^>++-- | Extract the first value, use the same output type+(.~~$>) :: forall m x xs a.+ ( Monad m+ ) => Variant (a ': xs) -> Flow m (x ': xs) -> Flow m (x ': xs)+{-# INLINE (.~~$>) #-}+(.~~$>) v f = v .~$> const f++infixl 0 .~~$>++-- | Extract the first value, use the same output type+(>.~~$>) :: forall m x xs a.+ ( Monad m+ ) => Flow m (a ': xs) -> Flow m (x ': xs) -> Flow m (x ': xs)+{-# INLINE (>.~~$>) #-}+(>.~~$>) = liftm (.~~$>)++infixl 0 >.~~$>++-- | Take the first output, fusion the result+(.~~|>) ::+ ( Liftable xs zs+ , Liftable ys zs+ , zs ~ Union xs ys+ , Monad m+ ) => Variant (a ': ys) -> Flow m xs -> Flow m zs+{-# INLINE (.~~|>) #-}+(.~~|>) v f = v .~|> const f++infixl 0 .~~|>++-- | Take the first output, fusion the result+(>.~~|>) ::+ ( Liftable xs zs+ , Liftable ys zs+ , zs ~ Union xs ys+ , Monad m+ ) => Flow m (a ': ys) -> Flow m xs -> Flow m zs+{-# INLINE (>.~~|>) #-}+(>.~~|>) = liftm (.~~|>)++infixl 0 >.~~|>++-- | Extract the first value and perform effect. Passthrough the input value+(.~~=>) ::+ ( Monad m+ ) => Variant (a ': l) -> m () -> Flow m (a ': l)+{-# INLINE (.~~=>) #-}+(.~~=>) v f = v .~=> const f++infixl 0 .~~=>++-- | Extract the first value and perform effect. Passthrough the input value+(>.~~=>) ::+ ( Monad m+ ) => Flow m (a ': l) -> m () -> Flow m (a ': l)+{-# INLINE (>.~~=>) #-}+(>.~~=>) = liftm (.~~=>)++infixl 0 >.~~=>++-- | Extract the first value and perform effect.+(.~~!>) ::+ ( Monad m+ ) => Variant (a ': l) -> m () -> m ()+{-# INLINE (.~~!>) #-}+(.~~!>) v f = v .~!> const f++infixl 0 .~~!>++-- | Extract the first value and perform effect.+(>.~~!>) ::+ ( Monad m+ ) => Flow m (a ': l) -> m () -> m ()+{-# INLINE (>.~~!>) #-}+(>.~~!>) = liftm (.~~!>)++infixl 0 >.~~!>+++----------------------------------------------------------+-- Tail operations+----------------------------------------------------------++-- | Extract the tail, set the first value+(..~.>) ::+ ( Monad m+ ) => Variant (a ': l) -> (Variant l -> m a) -> m a+{-# INLINE (..~.>) #-}+(..~.>) v f = makeFlowOp selectTail (applyVM f) combineSingle v++infixl 0 ..~.>++-- | Extract the tail, set the first value+(>..~.>) ::+ ( Monad m+ ) => Flow m (a ': l) -> (Variant l -> m a) -> m a+{-# INLINE (>..~.>) #-}+(>..~.>) = liftm (..~.>)++infixl 0 >..~.>++-- | Extract the tail, set the first value (pure function)+(..-.>) ::+ ( Monad m+ ) => Variant (a ': l) -> (Variant l -> a) -> m a+{-# INLINE (..-.>) #-}+(..-.>) v f = case headVariant v of+ Right u -> return u+ Left l -> return (f l)++infixl 0 ..-.>++-- | Extract the tail, set the first value (pure function)+(>..-.>) ::+ ( Monad m+ ) => Flow m (a ': l) -> (Variant l -> a) -> m a+{-# INLINE (>..-.>) #-}+(>..-.>) = liftm (..-.>)++infixl 0 >..-.>++-- | Extract the tail, set the tail+(..-..>) :: forall a l xs m.+ ( Monad m+ ) => Variant (a ': l) -> (Variant l -> Variant xs) -> Flow m (a ': xs)+{-# INLINE (..-..>) #-}+(..-..>) v f = case headVariant v of+ Right u -> flowSetN @0 u+ Left l -> return (prependVariant @'[a] (f l))++infixl 0 ..-..>++-- | Extract the tail, set the tail+(>..-..>) ::+ ( Monad m+ ) => Flow m (a ': l) -> (Variant l -> Variant xs) -> Flow m (a ': xs)+{-# INLINE (>..-..>) #-}+(>..-..>) = liftm (..-..>)++infixl 0 >..-..>++-- | Extract the tail, set the tail+(..~..>) :: forall a l xs m.+ ( Monad m+ ) => Variant (a ': l) -> (Variant l -> Flow m xs) -> Flow m (a ': xs)+{-# INLINE (..~..>) #-}+(..~..>) v f = case headVariant v of+ Right u -> flowSetN @0 u+ Left l -> prependVariant @'[a] <$> f l++infixl 0 ..~..>++-- | Extract the tail, set the tail+(>..~..>) ::+ ( Monad m+ ) => Flow m (a ': l) -> (Variant l -> Flow m xs) -> Flow m (a ': xs)+{-# INLINE (>..~..>) #-}+(>..~..>) = liftm (..~..>)++infixl 0 >..~..>++-- | Extract the tail, lift the result+(..~^^>) ::+ ( Monad m+ , Liftable xs (a ': zs)+ ) => Variant (a ': l) -> (Variant l -> Flow m xs) -> Flow m (a ': zs)+{-# INLINE (..~^^>) #-}+(..~^^>) v f = case headVariant v of+ Right u -> flowSetN @0 u+ Left l -> liftVariant <$> f l++infixl 0 ..~^^>++-- | Extract the tail, lift the result+(>..~^^>) ::+ ( Monad m+ , Liftable xs (a ': zs)+ ) => Flow m (a ': l) -> (Variant l -> Flow m xs) -> Flow m (a ': zs)+{-# INLINE (>..~^^>) #-}+(>..~^^>) = liftm (..~^^>)++infixl 0 >..~^^>++-- | Extract the tail, connect the result+(..~^>) ::+ ( Monad m+ , Member a zs+ ) => Variant (a ': l) -> (Variant l -> Flow m zs) -> Flow m zs+{-# INLINE (..~^>) #-}+(..~^>) v f = case headVariant v of+ Right u -> flowSet u+ Left l -> f l++infixl 0 ..~^>++-- | Extract the tail, connect the result+(>..~^>) ::+ ( Monad m+ , Member a zs+ ) => Flow m (a ': l) -> (Variant l -> Flow m zs) -> Flow m zs+{-# INLINE (>..~^>) #-}+(>..~^>) = liftm (..~^>)++infixl 0 >..~^>++-- | Match in the tail, connect to the expected result+(..?~^>) ::+ ( Monad m+ , MaybeCatchable a xs+ , Liftable (Filter a xs) ys+ ) => Variant (x ': xs) -> (a -> Flow m ys) -> Flow m (x ': ys)+{-# INLINE (..?~^>) #-}+(..?~^>) v f = v ..~..> (\v' -> v' ?~^> f)++infixl 0 ..?~^>++-- | Match in the tail, connect to the expected result+(>..?~^>) ::+ ( Monad m+ , MaybeCatchable a xs+ , Liftable (Filter a xs) ys+ ) => Flow m (x ': xs) -> (a -> Flow m ys) -> Flow m (x ': ys)+{-# INLINE (>..?~^>) #-}+(>..?~^>) = liftm (..?~^>)++infixl 0 >..?~^>++-- | Match in the tail, connect to the expected result+(..%~^>) ::+ ( Monad m+ , Catchable a xs+ , Liftable (Filter a xs) ys+ ) => Variant (x ': xs) -> (a -> Flow m ys) -> Flow m (x ': ys)+{-# INLINE (..%~^>) #-}+(..%~^>) v f = v ..~..> (\v' -> v' %~^> f)++infixl 0 ..%~^>++-- | Match in the tail, connect to the expected result+(>..%~^>) ::+ ( Monad m+ , Catchable a xs+ , Liftable (Filter a xs) ys+ ) => Flow m (x ': xs) -> (a -> Flow m ys) -> Flow m (x ': ys)+{-# INLINE (>..%~^>) #-}+(>..%~^>) = liftm (..%~^>)++infixl 0 >..%~^>++-- | Match in the tail, lift to the expected result+(..?~^^>) ::+ ( Monad m+ , MaybeCatchable a xs+ , Liftable (Filter a xs) zs+ , Liftable ys zs+ ) => Variant (x ': xs) -> (a -> Flow m ys) -> Flow m (x ': zs)+{-# INLINE (..?~^^>) #-}+(..?~^^>) v f = v ..~..> (\v' -> v' ?~^^> f)++infixl 0 ..?~^^>++-- | Match in the tail, lift to the expected result+(>..?~^^>) ::+ ( Monad m+ , MaybeCatchable a xs+ , Liftable (Filter a xs) zs+ , Liftable ys zs+ ) => Flow m (x ': xs) -> (a -> Flow m ys) -> Flow m (x ': zs)+{-# INLINE (>..?~^^>) #-}+(>..?~^^>) = liftm (..?~^^>)++infixl 0 >..?~^^>++-- | Match in the tail, lift to the expected result+(..%~^^>) ::+ ( Monad m+ , Catchable a xs+ , Liftable (Filter a xs) zs+ , Liftable ys zs+ ) => Variant (x ': xs) -> (a -> Flow m ys) -> Flow m (x ': zs)+{-# INLINE (..%~^^>) #-}+(..%~^^>) v f = v ..~..> (\v' -> v' %~^^> f)++infixl 0 ..%~^^>++-- | Match in the tail, lift to the expected result+(>..%~^^>) ::+ ( Monad m+ , Catchable a xs+ , Liftable (Filter a xs) zs+ , Liftable ys zs+ ) => Flow m (x ': xs) -> (a -> Flow m ys) -> Flow m (x ': zs)+{-# INLINE (>..%~^^>) #-}+(>..%~^^>) = liftm (..%~^^>)++infixl 0 >..%~^^>++-- | Match in the tail, keep the same types+(..?~$>) ::+ ( Monad m+ , MaybeCatchable a xs+ , Liftable (Filter a xs) (x ': xs)+ ) => Variant (x ': xs) -> (a -> Flow m (x ': xs)) -> Flow m (x ': xs)+{-# INLINE (..?~$>) #-}+(..?~$>) v f = case headVariant v of+ Right _ -> return v+ Left xs -> xs ?~^> f++infixl 0 ..?~$>++-- | Match in the tail, keep the same types+(>..?~$>) ::+ ( Monad m+ , MaybeCatchable a xs+ , Liftable (Filter a xs) (x ': xs)+ ) => Flow m (x ': xs) -> (a -> Flow m (x ': xs)) -> Flow m (x ': xs)+{-# INLINE (>..?~$>) #-}+(>..?~$>) = liftm (..?~$>)++infixl 0 >..?~$>++-- | Match in the tail, keep the same types+(..%~$>) ::+ ( Monad m+ , Catchable a xs+ , Liftable (Filter a xs) (x ': xs)+ ) => Variant (x ': xs) -> (a -> Flow m (x ': xs)) -> Flow m (x ': xs)+{-# INLINE (..%~$>) #-}+(..%~$>) v f = case headVariant v of+ Right _ -> return v+ Left xs -> xs %~^> f++infixl 0 ..%~$>++-- | Match in the tail, keep the same types+(>..%~$>) ::+ ( Monad m+ , Catchable a xs+ , Liftable (Filter a xs) (x ': xs)+ ) => Flow m (x ': xs) -> (a -> Flow m (x ': xs)) -> Flow m (x ': xs)+{-# INLINE (>..%~$>) #-}+(>..%~$>) = liftm (..%~$>)++infixl 0 >..%~$>+++-- | Extract the tail and perform an effect. Passthrough the input value+(..~=>) ::+ ( Monad m+ ) => Variant (x ': xs) -> (Variant xs -> m ()) -> Flow m (x ': xs)+{-# INLINE (..~=>) #-}+(..~=>) v f = case headVariant v of+ Right _ -> return v+ Left l -> f l >> return v++infixl 0 ..~=>++-- | Extract the tail and perform an effect. Passthrough the input value+(>..~=>) ::+ ( Monad m+ ) => Flow m (x ': xs) -> (Variant xs -> m ()) -> Flow m (x ': xs)+{-# INLINE (>..~=>) #-}+(>..~=>) = liftm (..~=>)++infixl 0 >..~=>++-- | Extract the tail and perform an effect+(..~!>) ::+ ( Monad m+ ) => Variant (x ': xs) -> (Variant xs -> m ()) -> m ()+{-# INLINE (..~!>) #-}+(..~!>) v f = case headVariant v of+ Right _ -> return ()+ Left l -> f l++infixl 0 ..~!>++-- | Extract the tail and perform an effect+(>..~!>) ::+ ( Monad m+ ) => Flow m (x ': xs) -> (Variant xs -> m ()) -> m ()+{-# INLINE (>..~!>) #-}+(>..~!>) = liftm (..~!>)++infixl 0 >..~!>++-- | Extract the tail and perform an effect+(..~!!>) ::+ ( Monad m+ ) => Variant (x ': xs) -> (Variant xs -> m ()) -> m x+{-# INLINE (..~!!>) #-}+(..~!!>) v f = case headVariant v of+ Right x -> return x+ Left xs -> f xs >> error "..~!!> error"++infixl 0 ..~!!>++-- | Extract the tail and perform an effect+(>..~!!>) ::+ ( Monad m+ ) => Flow m (x ': xs) -> (Variant xs -> m ()) -> m x+{-# INLINE (>..~!!>) #-}+(>..~!!>) = liftm (..~!!>)++infixl 0 >..~!!>++-- | Match in the tail and perform an effect+(..?~!!>) ::+ ( Monad m+ , MaybeCatchable y xs+ ) => Variant (x ': xs) -> (y -> m ()) -> Flow m (x ': Filter y xs)+{-# INLINE (..?~!!>) #-}+(..?~!!>) v f = v ..~..> (\xs -> xs ?~!!> f)++infixl 0 ..?~!!>++-- | Match in the tail and perform an effect+(>..?~!!>) ::+ ( Monad m+ , MaybeCatchable y xs+ ) => Flow m (x ': xs) -> (y -> m ()) -> Flow m (x ': Filter y xs)+{-# INLINE (>..?~!!>) #-}+(>..?~!!>) = liftm (..?~!!>)++infixl 0 >..?~!!>++-- | Match in the tail and perform an effect+(..%~!!>) ::+ ( Monad m+ , Catchable y xs+ ) => Variant (x ': xs) -> (y -> m ()) -> Flow m (x ': Filter y xs)+{-# INLINE (..%~!!>) #-}+(..%~!!>) v f = v ..~..> (\xs -> xs %~!!> f)++infixl 0 ..%~!!>++-- | Match in the tail and perform an effect+(>..%~!!>) ::+ ( Monad m+ , Catchable y xs+ ) => Flow m (x ': xs) -> (y -> m ()) -> Flow m (x ': Filter y xs)+{-# INLINE (>..%~!!>) #-}+(>..%~!!>) = liftm (..%~!!>)++infixl 0 >..%~!!>++-- | Match in the tail and perform an effect+(..?~!>) ::+ ( Monad m+ , MaybeCatchable y xs+ ) => Variant (x ': xs) -> (y -> m ()) -> m ()+{-# INLINE (..?~!>) #-}+(..?~!>) v f = case headVariant v of+ Right _ -> return ()+ Left xs -> xs ?~!> f++infixl 0 ..?~!>++-- | Match in the tail and perform an effect+(>..?~!>) ::+ ( Monad m+ , MaybeCatchable y xs+ ) => Flow m (x ': xs) -> (y -> m ()) -> m ()+{-# INLINE (>..?~!>) #-}+(>..?~!>) = liftm (..?~!>)++infixl 0 >..?~!>++-- | Match in the tail and perform an effect+(..%~!>) ::+ ( Monad m+ , Catchable y xs+ ) => Variant (x ': xs) -> (y -> m ()) -> m ()+{-# INLINE (..%~!>) #-}+(..%~!>) v f = case headVariant v of+ Right _ -> return ()+ Left xs -> xs %~!> f++infixl 0 ..%~!>++-- | Match in the tail and perform an effect+(>..%~!>) ::+ ( Monad m+ , Catchable y xs+ ) => Flow m (x ': xs) -> (y -> m ()) -> m ()+{-# INLINE (>..%~!>) #-}+(>..%~!>) = liftm (..%~!>)++infixl 0 >..%~!>++----------------------------------------------------------+-- Caught element operations+----------------------------------------------------------++-- | Catch element, set the first value+(?~.>) :: forall x xs y ys m.+ ( ys ~ Filter x xs+ , Monad m+ , MaybeCatchable x xs+ ) => Variant xs -> (x -> m y) -> Flow m (y ': ys)+{-# INLINE (?~.>) #-}+(?~.>) v f = case catchVariantMaybe v of+ Right x -> flowSetN @0 =<< f x+ Left ys -> prependVariant @'[y] <$> return ys++infixl 0 ?~.>++-- | Catch element, set the first value+(>?~.>) ::+ ( ys ~ Filter x xs+ , Monad m+ , MaybeCatchable x xs+ ) => Flow m xs -> (x -> m y) -> Flow m (y ': ys)+{-# INLINE (>?~.>) #-}+(>?~.>) = liftm (?~.>)++infixl 0 >?~.>++-- | Catch element, set the first value+(%~.>) :: forall x xs y ys m.+ ( ys ~ Filter x xs+ , Monad m+ , Catchable x xs+ ) => Variant xs -> (x -> m y) -> Flow m (y ': ys)+{-# INLINE (%~.>) #-}+(%~.>) = (?~.>)++infixl 0 %~.>++-- | Catch element, set the first value+(>%~.>) ::+ ( ys ~ Filter x xs+ , Monad m+ , Catchable x xs+ ) => Flow m xs -> (x -> m y) -> Flow m (y ': ys)+{-# INLINE (>%~.>) #-}+(>%~.>) = liftm (%~.>)++infixl 0 >%~.>++-- | Catch element, concat the result+(?~+>) :: forall x xs ys m.+ ( Monad m+ , MaybeCatchable x xs+ , KnownNat (Length ys)+ ) => Variant xs -> (x -> Flow m ys) -> Flow m (Concat ys (Filter x xs))+{-# INLINE (?~+>) #-}+(?~+>) v f = case catchVariantMaybe v of+ Right x -> appendVariant @(Filter x xs) <$> f x+ Left ys -> prependVariant @ys <$> return ys++infixl 0 ?~+>++-- | Catch element, concat the result+(>?~+>) :: forall x xs ys m.+ ( Monad m+ , MaybeCatchable x xs+ , KnownNat (Length ys)+ ) => Flow m xs -> (x -> Flow m ys) -> Flow m (Concat ys (Filter x xs))+{-# INLINE (>?~+>) #-}+(>?~+>) = liftm (?~+>)++infixl 0 >?~+>++-- | Catch element, concat the result+(%~+>) :: forall x xs ys m.+ ( Monad m+ , Catchable x xs+ , KnownNat (Length ys)+ ) => Variant xs -> (x -> Flow m ys) -> Flow m (Concat ys (Filter x xs))+{-# INLINE (%~+>) #-}+(%~+>) = (?~+>)++infixl 0 %~+>++-- | Catch element, concat the result+(>%~+>) :: forall x xs ys m.+ ( Monad m+ , Catchable x xs+ , KnownNat (Length ys)+ ) => Flow m xs -> (x -> Flow m ys) -> Flow m (Concat ys (Filter x xs))+{-# INLINE (>%~+>) #-}+(>%~+>) = liftm (%~+>)++infixl 0 >%~+>++-- | Catch element, lift the result+(?~^^>) :: forall x xs ys zs m.+ ( Monad m+ , MaybeCatchable x xs+ , Liftable (Filter x xs) zs+ , Liftable ys zs+ ) => Variant xs -> (x -> Flow m ys) -> Flow m zs+{-# INLINE (?~^^>) #-}+(?~^^>) v f = case catchVariantMaybe v of+ Right x -> liftVariant <$> f x+ Left ys -> liftVariant <$> return ys++infixl 0 ?~^^>++-- | Catch element, lift the result+(>?~^^>) :: forall x xs ys zs m.+ ( Monad m+ , MaybeCatchable x xs+ , Liftable (Filter x xs) zs+ , Liftable ys zs+ ) => Flow m xs -> (x -> Flow m ys) -> Flow m zs+{-# INLINE (>?~^^>) #-}+(>?~^^>) = liftm (?~^^>)++infixl 0 >?~^^>++-- | Catch element, lift the result+(%~^^>) :: forall x xs ys zs m.+ ( Monad m+ , Catchable x xs+ , Liftable (Filter x xs) zs+ , Liftable ys zs+ ) => Variant xs -> (x -> Flow m ys) -> Flow m zs+{-# INLINE (%~^^>) #-}+(%~^^>) = (?~^^>)++infixl 0 %~^^>++-- | Catch element, lift the result+(>%~^^>) :: forall x xs ys zs m.+ ( Monad m+ , Catchable x xs+ , Liftable (Filter x xs) zs+ , Liftable ys zs+ ) => Flow m xs -> (x -> Flow m ys) -> Flow m zs+{-# INLINE (>%~^^>) #-}+(>%~^^>) = liftm (%~^^>)++infixl 0 >%~^^>++-- | Catch element, connect to the expected output+(?~^>) :: forall x xs zs m.+ ( Monad m+ , MaybeCatchable x xs+ , Liftable (Filter x xs) zs+ ) => Variant xs -> (x -> Flow m zs) -> Flow m zs+{-# INLINE (?~^>) #-}+(?~^>) v f = case catchVariantMaybe v of+ Right x -> f x+ Left ys -> return (liftVariant ys)++infixl 0 ?~^>++-- | Catch element, connect to the expected output+(>?~^>) :: forall x xs zs m.+ ( Monad m+ , MaybeCatchable x xs+ , Liftable (Filter x xs) zs+ ) => Flow m xs -> (x -> Flow m zs) -> Flow m zs+{-# INLINE (>?~^>) #-}+(>?~^>) = liftm (?~^>)++infixl 0 >?~^>++-- | Catch element, connect to the expected output+(%~^>) :: forall x xs zs m.+ ( Monad m+ , Catchable x xs+ , Liftable (Filter x xs) zs+ ) => Variant xs -> (x -> Flow m zs) -> Flow m zs+{-# INLINE (%~^>) #-}+(%~^>) = (?~^>)++infixl 0 %~^>++-- | Catch element, connect to the expected output+(>%~^>) :: forall x xs zs m.+ ( Monad m+ , Catchable x xs+ , Liftable (Filter x xs) zs+ ) => Flow m xs -> (x -> Flow m zs) -> Flow m zs+{-# INLINE (>%~^>) #-}+(>%~^>) = liftm (%~^>)++infixl 0 >%~^>++-- | Catch element, use the same output type+(?~$>) :: forall x xs m.+ ( Monad m+ , MaybeCatchable x xs+ ) => Variant xs -> (x -> Flow m xs) -> Flow m xs+{-# INLINE (?~$>) #-}+(?~$>) v f = case catchVariantMaybe v of+ Right x -> f x+ Left _ -> return v++infixl 0 ?~$>++-- | Catch element, use the same output type+(>?~$>) :: forall x xs m.+ ( Monad m+ , MaybeCatchable x xs+ ) => Flow m xs -> (x -> Flow m xs) -> Flow m xs+{-# INLINE (>?~$>) #-}+(>?~$>) = liftm (?~$>)++infixl 0 >?~$>++-- | Catch element, use the same output type+(%~$>) :: forall x xs m.+ ( Monad m+ , Catchable x xs+ ) => Variant xs -> (x -> Flow m xs) -> Flow m xs+{-# INLINE (%~$>) #-}+(%~$>) = (?~$>)++infixl 0 %~$>++-- | Catch element, use the same output type+(>%~$>) :: forall x xs m.+ ( Monad m+ , Catchable x xs+ ) => Flow m xs -> (x -> Flow m xs) -> Flow m xs+{-# INLINE (>%~$>) #-}+(>%~$>) = liftm (%~$>)++infixl 0 >%~$>++-- | Catch element, fusion the result+(?~|>) :: forall x xs ys zs m.+ ( Monad m+ , MaybeCatchable x xs+ , Liftable (Filter x xs) zs+ , Liftable ys zs+ , zs ~ Union (Filter x xs) ys+ ) => Variant xs -> (x -> Flow m ys) -> Flow m zs+{-# INLINE (?~|>) #-}+(?~|>) v f = case catchVariantMaybe v of+ Right x -> liftVariant <$> f x+ Left ys -> return (liftVariant ys)++infixl 0 ?~|>++-- | Catch element, fusion the result+(>?~|>) :: forall x xs ys zs m.+ ( Monad m+ , MaybeCatchable x xs+ , Liftable (Filter x xs) zs+ , Liftable ys zs+ , zs ~ Union (Filter x xs) ys+ ) => Flow m xs -> (x -> Flow m ys) -> Flow m zs+{-# INLINE (>?~|>) #-}+(>?~|>) = liftm (?~|>)++infixl 0 >?~|>++-- | Catch element, fusion the result+(%~|>) :: forall x xs ys zs m.+ ( Monad m+ , Catchable x xs+ , Liftable (Filter x xs) zs+ , Liftable ys zs+ , zs ~ Union (Filter x xs) ys+ ) => Variant xs -> (x -> Flow m ys) -> Flow m zs+{-# INLINE (%~|>) #-}+(%~|>) = (?~|>)++infixl 0 %~|>++-- | Catch element, fusion the result+(>%~|>) :: forall x xs ys zs m.+ ( Monad m+ , Catchable x xs+ , Liftable (Filter x xs) zs+ , Liftable ys zs+ , zs ~ Union (Filter x xs) ys+ ) => Flow m xs -> (x -> Flow m ys) -> Flow m zs+{-# INLINE (>%~|>) #-}+(>%~|>) = liftm (%~|>)++infixl 0 >%~|>++-- | Catch element and perform effect. Passthrough the input value.+(?~=>) :: forall x xs m.+ ( Monad m+ , MaybeCatchable x xs+ ) => Variant xs -> (x -> m ()) -> Flow m xs+{-# INLINE (?~=>) #-}+(?~=>) v f = case catchVariantMaybe v of+ Right x -> f x >> return v+ Left _ -> return v++infixl 0 ?~=>++-- | Catch element and perform effect. Passthrough the input value.+(>?~=>) :: forall x xs m.+ ( Monad m+ , MaybeCatchable x xs+ ) => Flow m xs -> (x -> m ()) -> Flow m xs+{-# INLINE (>?~=>) #-}+(>?~=>) = liftm (?~=>)++infixl 0 >?~=>++-- | Catch element and perform effect. Passthrough the input value.+(%~=>) :: forall x xs m.+ ( Monad m+ , Catchable x xs+ ) => Variant xs -> (x -> m ()) -> Flow m xs+{-# INLINE (%~=>) #-}+(%~=>) = (?~=>)++infixl 0 %~=>++-- | Catch element and perform effect. Passthrough the input value.+(>%~=>) :: forall x xs m.+ ( Monad m+ , Catchable x xs+ ) => Flow m xs -> (x -> m ()) -> Flow m xs+{-# INLINE (>%~=>) #-}+(>%~=>) = liftm (%~=>)++infixl 0 >%~=>++-- | Catch element and perform effect.+(?~!>) :: forall x xs m.+ ( Monad m+ , MaybeCatchable x xs+ ) => Variant xs -> (x -> m ()) -> m ()+{-# INLINE (?~!>) #-}+(?~!>) v f = case catchVariantMaybe v of+ Right x -> f x+ Left _ -> return ()++infixl 0 ?~!>++-- | Catch element and perform effect.+(>?~!>) :: forall x xs m.+ ( Monad m+ , MaybeCatchable x xs+ ) => Flow m xs -> (x -> m ()) -> m ()+{-# INLINE (>?~!>) #-}+(>?~!>) = liftm (?~!>)++infixl 0 >?~!>++-- | Catch element and perform effect.+(%~!>) :: forall x xs m.+ ( Monad m+ , Catchable x xs+ ) => Variant xs -> (x -> m ()) -> m ()+{-# INLINE (%~!>) #-}+(%~!>) = (?~!>)++infixl 0 %~!>++-- | Catch element and perform effect.+(>%~!>) :: forall x xs m.+ ( Monad m+ , Catchable x xs+ ) => Flow m xs -> (x -> m ()) -> m ()+{-# INLINE (>%~!>) #-}+(>%~!>) = liftm (%~!>)++infixl 0 >%~!>++-- | Catch element and perform effect.+(?~!!>) :: forall x xs m.+ ( Monad m+ , MaybeCatchable x xs+ ) => Variant xs -> (x -> m ()) -> Flow m (Filter x xs)+{-# INLINE (?~!!>) #-}+(?~!!>) v f = case catchVariantMaybe v of+ Right x -> f x >> error "?~!!> error"+ Left u -> return u++infixl 0 ?~!!>++-- | Catch element and perform effect.+(>?~!!>) :: forall x xs m.+ ( Monad m+ , MaybeCatchable x xs+ ) => Flow m xs -> (x -> m ()) -> Flow m (Filter x xs)+{-# INLINE (>?~!!>) #-}+(>?~!!>) = liftm (?~!!>)++infixl 0 >?~!!>++-- | Catch element and perform effect.+(%~!!>) :: forall x xs m.+ ( Monad m+ , Catchable x xs+ ) => Variant xs -> (x -> m ()) -> Flow m (Filter x xs)+{-# INLINE (%~!!>) #-}+(%~!!>) = (?~!!>)++infixl 0 %~!!>++-- | Catch element and perform effect.+(>%~!!>) :: forall x xs m.+ ( Monad m+ , Catchable x xs+ ) => Flow m xs -> (x -> m ()) -> Flow m (Filter x xs)+{-# INLINE (>%~!!>) #-}+(>%~!!>) = liftm (%~!!>)++infixl 0 >%~!!>++--------------------------------------------------------------+-- Helpers+--------------------------------------------------------------+++-- | Make a flow operator+makeFlowOp :: Monad m =>+ (Variant as -> Either (Variant bs) (Variant cs))+ -> (Variant cs -> Flow m ds)+ -> (Either (Variant bs) (Variant ds) -> es)+ -> Variant as -> m es+{-# INLINE makeFlowOp #-}+makeFlowOp select apply combine v = combine <$> traverse apply (select v)++-- | Make a flow operator+makeFlowOpM :: Monad m =>+ (Variant as -> Either (Variant bs) (Variant cs))+ -> (Variant cs -> Flow m ds)+ -> (Either (Variant bs) (Variant ds) -> es)+ -> Flow m as -> m es+{-# INLINE makeFlowOpM #-}+makeFlowOpM select apply combine v = v >>= makeFlowOp select apply combine+++-- | Select the first value+selectFirst :: Variant (x ': xs) -> Either (Variant xs) (Variant '[x])+{-# INLINE selectFirst #-}+selectFirst = fmap (setVariantN @0) . headVariant++-- | Select the tail+selectTail :: Variant (x ': xs) -> Either (Variant '[x]) (Variant xs)+{-# INLINE selectTail #-}+selectTail = flipEither . selectFirst+ where+ flipEither (Left x) = Right x+ flipEither (Right x) = Left x++-- | Select by type+selectType ::+ ( Catchable x xs+ ) => Variant xs -> Either (Variant (Filter x xs)) (Variant '[x])+{-# INLINE selectType #-}+selectType = fmap (setVariantN @0) . catchVariant++-- | Const application+applyConst :: Flow m ys -> (Variant xs -> Flow m ys)+{-# INLINE applyConst #-}+applyConst = const++-- | Pure application+applyPure :: Monad m => (Variant xs -> Variant ys) -> Variant xs -> Flow m ys+{-# INLINE applyPure #-}+applyPure f = return . f++-- | Lift a monadic function+applyM :: Monad m => (a -> m b) -> Variant '[a] -> Flow m '[b]+{-# INLINE applyM #-}+applyM = liftF++-- | Lift a monadic function+applyVM :: Monad m => (Variant a -> m b) -> Variant a -> Flow m '[b]+{-# INLINE applyVM #-}+applyVM f = fmap (setVariantN @0) . f++-- | Lift a monadic function+applyF :: (a -> Flow m b) -> Variant '[a] -> Flow m b+{-# INLINE applyF #-}+applyF f = f . singleVariant++-- | Set the first value (the "correct" one)+combineFirst :: forall x xs. Either (Variant xs) (Variant '[x]) -> Variant (x ': xs)+{-# INLINE combineFirst #-}+combineFirst = \case+ Right x -> appendVariant @xs x+ Left xs -> prependVariant @'[x] xs++-- | Set the first value, keep the same tail type +combineSameTail :: forall x xs.+ Either (Variant xs) (Variant (x ': xs)) -> Variant (x ': xs)+{-# INLINE combineSameTail #-}+combineSameTail = \case+ Right x -> x+ Left xs -> prependVariant @'[x] xs++-- | Return the valid variant unmodified+combineEither :: Either (Variant xs) (Variant xs) -> Variant xs+{-# INLINE combineEither #-}+combineEither = \case+ Right x -> x+ Left x -> x++-- | Concatenate unselected values+combineConcat :: forall xs ys.+ ( KnownNat (Length xs)+ ) => Either (Variant ys) (Variant xs) -> Variant (Concat xs ys)+{-# INLINE combineConcat #-}+combineConcat = \case+ Right xs -> appendVariant @ys xs+ Left ys -> prependVariant @xs ys++-- | Union+combineUnion ::+ ( Liftable xs (Union xs ys)+ , Liftable ys (Union xs ys)+ ) => Either (Variant ys) (Variant xs) -> Variant (Union xs ys)+{-# INLINE combineUnion #-}+combineUnion = \case+ Right xs -> liftVariant xs+ Left ys -> liftVariant ys++-- | Lift unselected+combineLiftUnselected ::+ ( Liftable ys xs+ ) => Either (Variant ys) (Variant xs) -> Variant xs+{-# INLINE combineLiftUnselected #-}+combineLiftUnselected = \case+ Right xs -> xs+ Left ys -> liftVariant ys++-- | Lift both+combineLiftBoth ::+ ( Liftable ys zs+ , Liftable xs zs+ ) => Either (Variant ys) (Variant xs) -> Variant zs+{-# INLINE combineLiftBoth #-}+combineLiftBoth = \case+ Right xs -> liftVariant xs+ Left ys -> liftVariant ys++-- | Single value+combineSingle :: Either (Variant '[x]) (Variant '[x]) -> x+{-# INLINE combineSingle #-}+combineSingle = \case+ Right x -> singleVariant x+ Left x -> singleVariant x+++-- | Lift a pure function into a Variant to Variant function+liftV :: (a -> b) -> Variant '[a] -> Variant '[b]+liftV = updateVariantN @0++-- | Lift a function into a Flow+liftF :: Monad m => (a -> m b) -> Variant '[a] -> Flow m '[b]+liftF = updateVariantM @0
+ src/lib/Haskus/Utils/HArray.hs view
@@ -0,0 +1,137 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE ExistentialQuantification #-}+{-# LANGUAGE RoleAnnotations #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE AllowAmbiguousTypes #-}++-- | Heterogeneous array: like a HList but indexed in O(1)+module Haskus.Utils.HArray+ ( HArray+ , HArrayIndex+ , HArrayIndexT+ , HArrayTryIndexT+ , emptyHArray+ , singleHArray+ , getHArrayN+ , getHArray0+ , setHArrayN+ , getHArrayT+ , setHArrayT+ , tryGetHArrayT+ , appendHArray+ , prependHArray+ , concatHArray+ , initHArray+ , tailHArray+ , HArrayT (..)+ , (>~:~>)+ )+where++import Data.Vector as V+import Unsafe.Coerce++import Haskus.Utils.Types.List+import Haskus.Utils.Types+import Haskus.Utils.Flow++-- | heterogeneous array+data HArray (types :: [*]) = forall a. HArray (Vector a)++type role HArray representational++-- | Empty array+emptyHArray :: HArray '[]+emptyHArray = HArray V.empty++-- | Empty array+singleHArray :: a -> HArray '[a]+singleHArray = HArray . V.singleton++-- | The type `t` with index `n` is indexable in the array+type HArrayIndex (n :: Nat) t (ts :: [*]) =+ ( KnownNat n+ , t ~ Index n ts+ , KnownNat (Length ts)+ , CmpNat n (Length ts) ~ 'LT+ )++-- | A type `t` is indexable in the array+type HArrayIndexT t (ts :: [*]) =+ ( IsMember t ts ~ 'True+ , HArrayIndex (IndexOf t ts) t ts+ )++-- | A type `t` is maybe indexable in the array+type HArrayTryIndexT t (ts :: [*]) =+ ( HArrayIndex (MaybeIndexOf t ts) t (t ': ts)+ )+++-- | Get an element by index+getHArrayN :: forall (n :: Nat) (ts :: [*]) t.+ ( HArrayIndex n t ts) => HArray ts -> t+getHArrayN (HArray as) = unsafeCoerce (as ! natValue @n)++-- | Get first element+getHArray0 :: (HArrayIndex 0 t ts) => HArray ts -> t+getHArray0 = getHArrayN @0++-- | Set an element by index+setHArrayN :: forall (n :: Nat) (ts :: [*]) t.+ (HArrayIndex n t ts) => t -> HArray ts -> HArray ts+setHArrayN a (HArray as) = HArray (as V.// [(natValue @n,unsafeCoerce a)])++-- | Get an element by type (select the first one with this type)+getHArrayT :: forall t ts.+ (HArrayIndexT t ts) => HArray ts -> t+getHArrayT = getHArrayN @(IndexOf t ts)++-- | Set an element by type (select the first one with this type)+setHArrayT :: forall t ts.+ (HArrayIndexT t ts) => t -> HArray ts -> HArray ts+setHArrayT = setHArrayN @(IndexOf t ts)++-- | Get an element by type (select the first one with this type)+tryGetHArrayT :: forall t ts.+ (HArrayTryIndexT t ts) => HArray ts -> Maybe t+tryGetHArrayT as = if n == 0+ then Nothing+ else Just $ getHArrayN @(MaybeIndexOf t ts) as'+ where+ n = natValue' @(MaybeIndexOf t ts)+ as' :: HArray (t ': ts)+ as' = prependHArray undefined as++-- | Append a value to an array (O(n))+appendHArray :: HArray ts -> t -> HArray (Snoc ts t)+appendHArray (HArray as) a = HArray (V.snoc as (unsafeCoerce a))++-- | Prepend a value to an array (O(n))+prependHArray :: t -> HArray ts -> HArray (t ': ts)+prependHArray a (HArray as) = HArray (V.cons (unsafeCoerce a) as)++-- | Concat arrays+concatHArray :: HArray ts1 -> HArray ts2 -> HArray (Concat ts1 ts2)+concatHArray (HArray as1) (HArray as2) = HArray (V.concat [as1,unsafeCoerce as2])++-- | Drop the last element+initHArray :: HArray ts -> HArray (Init ts)+initHArray (HArray as) = HArray (V.init as)++-- | Drop the first element+tailHArray :: HArray ts -> HArray (Tail ts)+tailHArray (HArray as) = HArray (V.tail as)++newtype HArrayT m xs ys = HArrayT+ { runHArrayT :: HArray xs -> m (HArray ys)+ }++-- | Compose HArrayT+(>~:~>) :: (Monad m) => HArrayT m xs ys -> HArrayT m ys zs -> HArrayT m xs zs+(>~:~>) (HArrayT f) (HArrayT g) = HArrayT (f >=> g)
+ src/lib/Haskus/Utils/HList.hs view
@@ -0,0 +1,252 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE FunctionalDependencies #-}+{-# LANGUAGE StandaloneDeriving #-}++-- | Heterogeneous list utils+module Haskus.Utils.HList+ ( HList (..)+ , hHead+ , hTail+ , hLength+ , hAppend+ , HFoldr' (..)+ , HFoldl' (..)+ , HTuple' (..)+ , Apply (..)+ , HZipList+ , hZipList+ , HFoldr+ , hFoldr+ , HFoldl+ , hFoldl+ , HReverse (..)+ )+where++import Haskus.Utils.Tuple+import Haskus.Utils.Types+import Haskus.Utils.Types.List++-- | Heterogeneous list+data family HList (l :: [*])+data instance HList '[] = HNil+data instance HList (x ': xs) = x `HCons` HList xs++infixr 2 `HCons`++deriving instance Eq (HList '[])+deriving instance (Eq x, Eq (HList xs)) => Eq (HList (x ': xs))++deriving instance Ord (HList '[])+deriving instance (Ord x, Ord (HList xs)) => Ord (HList (x ': xs))+++instance Show (HList '[]) where+ show _ = "H[]"++instance (Show e, Show (HList l)) => Show (HList (e ': l)) where+ show (HCons x l) = let 'H':'[':s = show l+ in "H[" ++ show x +++ (if s == "]" then s else "," ++ s)++-- | Head+hHead :: HList (e ': l) -> e+hHead (HCons x _) = x++-- | Tail+hTail :: HList (e ': l) -> HList l+hTail (HCons _ l) = l++-- | Length+hLength :: forall xs. (KnownNat (Length xs)) => HList xs -> Word+hLength _ = natValue' @(Length xs)++class HAppendList l1 l2 where+ hAppend :: HList l1 -> HList l2 -> HList (Concat l1 l2)++instance HAppendList '[] l2 where+ hAppend HNil l = l++instance HAppendList l l' => HAppendList (x ': l) l' where+ hAppend (HCons x l) l' = HCons x (hAppend l l')+++-- | Apply the function identified by the data type f from type a to type b.+class Apply f a b where+ apply :: f -> a -> b++--------------------------------------+-- Folding+--------------------------------------++class HFoldr f v (l :: [*]) r where+ hFoldr :: f -> v -> HList l -> r++instance (v ~ v') => HFoldr f v '[] v' where+ hFoldr _ v _ = v++instance+ ( Apply f (e, r) r'+ , HFoldr f v l r+ ) => HFoldr f v (e ': l) r'+ where+ hFoldr f v (HCons x l) = apply f (x, hFoldr f v l :: r)+++-- | Like HFoldr but only use types, not values!+--+-- It allows us to foldr over a list of types, without any associated hlist of+-- values.+class HFoldr' f v (l :: [*]) r where+ hFoldr' :: f -> v -> HList l -> r++instance (v ~ v') => HFoldr' f v '[] v' where+ hFoldr' _ v _ = v++instance+ ( Apply f (e, r) r'+ , HFoldr' f v l r+ ) => HFoldr' f v (e ': l) r'+ where+ -- compared to hFoldr, we pass undefined values instead of the values+ -- supposedly in the list (we don't have a real list associated to HList l)+ hFoldr' f v _ = apply f (undefined :: e, hFoldr' f v (undefined :: HList l) :: r)++class HFoldl f (z :: *) xs (r :: *) where+ hFoldl :: f -> z -> HList xs -> r++instance forall f z z' r x zx xs.+ ( zx ~ (z,x)+ , Apply f zx z'+ , HFoldl f z' xs r+ ) => HFoldl f z (x ': xs) r+ where+ hFoldl f z (x `HCons` xs) = hFoldl f (apply f (z,x) :: z') xs++instance (z ~ z') => HFoldl f z '[] z' where+ hFoldl _ z _ = z++-- | Like HFoldl but only use types, not values!+--+-- It allows us to foldr over a list of types, without any associated hlist of+-- values.+class HFoldl' f (z :: *) xs (r :: *) where+ hFoldl' :: f -> z -> HList xs -> r++instance forall f z z' r x zx xs.+ ( zx ~ (z,x)+ , Apply f zx z'+ , HFoldl' f z' xs r+ ) => HFoldl' f z (x ': xs) r+ where+ hFoldl' f z (_ `HCons` xs) = hFoldl' f (apply f (z,(undefined :: x)) :: z') xs++instance (z ~ z') => HFoldl' f z '[] z' where+ hFoldl' _ z _ = z++++class HZipList x y l | x y -> l, l -> x y where+ hZipList :: HList x -> HList y -> HList l+ hUnzipList :: HList l -> (HList x, HList y)++instance HZipList '[] '[] '[] where+ hZipList _ _ = HNil+ hUnzipList _ = (HNil, HNil)++instance ((x,y)~z, HZipList xs ys zs) => HZipList (x ': xs) (y ': ys) (z ': zs) where+ hZipList (HCons x xs) (HCons y ys) = (x,y) `HCons` hZipList xs ys+ hUnzipList (HCons ~(x,y) zs) = let ~(xs,ys) = hUnzipList zs in (x `HCons` xs, y `HCons` ys)+++class HRevApp l1 l2 l3 | l1 l2 -> l3 where+ hRevApp :: HList l1 -> HList l2 -> HList l3++instance HRevApp '[] l2 l2 where+ hRevApp _ l = l++instance HRevApp l (x ': l') z => HRevApp (x ': l) l' z where+ hRevApp (HCons x l) l' = hRevApp l (HCons x l')++++class HReverse xs sx | xs -> sx, sx -> xs where+ hReverse :: HList xs -> HList sx++instance+ ( HRevApp xs '[] sx+ , HRevApp sx '[] xs+ ) => HReverse xs sx+ where+ hReverse l = hRevApp l HNil+++--------------------------------------+-- Tuple convertion+--------------------------------------++-- * Conversion to and from tuples++-- | Convert between hlists and tuples+class HTuple' v t | v -> t, t -> v where+ -- | Convert an heterogeneous list into a tuple+ hToTuple' :: HList v -> t+ + -- | Convert a tuple into an heterogeneous list+ hFromTuple' :: t -> HList v+++instance HTuple' '[] () where+ hToTuple' HNil = ()+ hFromTuple' () = HNil++instance HTuple' '[a] (Single a) where+ hToTuple' (a `HCons` HNil) = Single a+ hFromTuple' (Single a) = a `HCons` HNil++instance HTuple' '[a,b] (a,b) where+ hToTuple' (a `HCons` b `HCons` HNil) = (a,b)+ hFromTuple' (a,b) = a `HCons` b `HCons` HNil++instance HTuple' '[a,b,c] (a,b,c) where+ hToTuple' (a `HCons` b `HCons` c `HCons` HNil) = (a,b,c)+ hFromTuple' (a,b,c) = a `HCons` b `HCons` c `HCons` HNil++instance HTuple' '[a,b,c,d] (a,b,c,d) where+ hToTuple' (a `HCons` b `HCons` c `HCons` d `HCons` HNil) = (a,b,c,d)+ hFromTuple' (a,b,c,d) = a `HCons` b `HCons` c `HCons` d `HCons` HNil++instance HTuple' '[a,b,c,d,e] (a,b,c,d,e) where+ hToTuple' (a `HCons` b `HCons` c `HCons` d `HCons` e `HCons` HNil) = (a,b,c,d,e)+ hFromTuple' (a,b,c,d,e) = a `HCons` b `HCons` c `HCons` d `HCons` e `HCons` HNil++instance HTuple' '[a,b,c,d,e,f] (a,b,c,d,e,f) where+ hToTuple' (a `HCons` b `HCons` c `HCons` d `HCons` e `HCons` f `HCons` HNil) = (a,b,c,d,e,f)+ hFromTuple' (a,b,c,d,e,f) = a `HCons` b `HCons` c `HCons` d `HCons` e `HCons` f `HCons` HNil++instance HTuple' '[a,b,c,d,e,f,g] (a,b,c,d,e,f,g) where+ hToTuple' (a `HCons` b `HCons` c `HCons` d `HCons` e `HCons` f `HCons` g `HCons` HNil) = (a,b,c,d,e,f,g)+ hFromTuple' (a,b,c,d,e,f,g) = a `HCons` b `HCons` c `HCons` d `HCons` e `HCons` f `HCons` g `HCons` HNil++instance HTuple' '[a,b,c,d,e,f,g,h] (a,b,c,d,e,f,g,h) where+ hToTuple' (a `HCons` b `HCons` c `HCons` d `HCons` e `HCons` f `HCons` g `HCons` h `HCons` HNil) = (a,b,c,d,e,f,g,h)+ hFromTuple' (a,b,c,d,e,f,g,h) = a `HCons` b `HCons` c `HCons` d `HCons` e `HCons` f `HCons` g `HCons` h `HCons` HNil++instance HTuple' '[a,b,c,d,e,f,g,h,i] (a,b,c,d,e,f,g,h,i) where+ hToTuple' (a `HCons` b `HCons` c `HCons` d `HCons` e `HCons` f `HCons` g `HCons` h `HCons` i `HCons` HNil) = (a,b,c,d,e,f,g,h,i)+ hFromTuple' (a,b,c,d,e,f,g,h,i) = a `HCons` b `HCons` c `HCons` d `HCons` e `HCons` f `HCons` g `HCons` h `HCons` i `HCons` HNil++instance HTuple' '[a,b,c,d,e,f,g,h,i,j] (a,b,c,d,e,f,g,h,i,j) where+ hToTuple' (a `HCons` b `HCons` c `HCons` d `HCons` e `HCons` f `HCons` g `HCons` h `HCons` i `HCons` j `HCons` HNil) = (a,b,c,d,e,f,g,h,i,j)+ hFromTuple' (a,b,c,d,e,f,g,h,i,j) = a `HCons` b `HCons` c `HCons` d `HCons` e `HCons` f `HCons` g `HCons` h `HCons` i `HCons` j `HCons` HNil
+ src/lib/Haskus/Utils/List.hs view
@@ -0,0 +1,14 @@+module Haskus.Utils.List+ ( checkLength+ , module Data.List+ )+where++import Data.List++-- | Check that a list has the given length (support infinite lists)+checkLength :: Word -> [a] -> Bool+checkLength 0 [] = True+checkLength 0 _ = False+checkLength _ [] = False+checkLength i (_:xs) = checkLength (i-1) xs
+ src/lib/Haskus/Utils/Map.hs view
@@ -0,0 +1,6 @@+module Haskus.Utils.Map+ ( module Data.Map+ )+where++import Data.Map
+ src/lib/Haskus/Utils/Maybe.hs view
@@ -0,0 +1,27 @@+{-# LANGUAGE LambdaCase #-}++-- | Utils for Maybe data type+module Haskus.Utils.Maybe+ ( onNothing+ , onNothingM+ , fromMaybeM+ , module Data.Maybe+ )+where++import Data.Maybe++-- | Flipped `fromMaybe`+onNothing :: Maybe a -> a -> a+onNothing = flip fromMaybe++-- | Flipped `fromMaybeM`+onNothingM :: Monad m => m (Maybe a) -> m a -> m a+onNothingM = flip fromMaybeM++-- | fromMaybe in a Monad+fromMaybeM :: Monad m => m a -> m (Maybe a) -> m a+fromMaybeM v f = f >>= \case+ Nothing -> v+ Just x -> return x+
+ src/lib/Haskus/Utils/Monad.hs view
@@ -0,0 +1,43 @@+{-# LANGUAGE Rank2Types #-}+{-# LANGUAGE TypeFamilies #-}++-- | Utils for Monads+module Haskus.Utils.Monad+ ( MonadInIO (..)+ , module Control.Monad+ , module Control.Monad.IO.Class+ , module Control.Monad.Extra+ , module Control.Monad.Trans.Class+ )+where++import Control.Monad.IO.Class+import Control.Monad.Trans.Class+import Control.Monad+import Control.Monad.Extra+import Control.Monad.State++class MonadIO m => MonadInIO m where+ -- | Lift with*-like functions into IO (alloca, etc.)+ liftWith :: (forall c. (a -> IO c) -> IO c) -> (a -> m b) -> m b++ -- | Lift with*-like functions into IO (alloca, etc.)+ liftWith2 :: (forall c. (a -> b -> IO c) -> IO c) -> (a -> b -> m e) -> m e++instance MonadInIO IO where+ {-# INLINE liftWith #-}+ liftWith = id++ {-# INLINE liftWith2 #-}+ liftWith2 = id++instance MonadInIO m => MonadInIO (StateT s m) where+ {-# INLINE liftWith #-}+ liftWith wth f =+ StateT $ \s -> do+ liftWith wth (\a -> runStateT (f a) s)++ {-# INLINE liftWith2 #-}+ liftWith2 wth f =+ StateT $ \s ->+ liftWith2 wth (\a b -> runStateT (f a b) s)
+ src/lib/Haskus/Utils/MultiState.hs view
@@ -0,0 +1,101 @@+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE ExistentialQuantification #-}+{-# LANGUAGE ScopedTypeVariables #-}++-- | State monad with multiple states (extensible)+--+-- Similar to the multistate package, with the following differences (as of+-- 0.7.0.0):+-- * don't pollute Data.HList.HList+-- * use HArray instead of a HList, for fast indexing+module Haskus.Utils.MultiState+ ( MStateT+ , MState+ , mSet+ , mGet+ , mTryGet+ , mModify+ , mModify'+ , mWith+ , runMState+ , evalMState+ , execMState+ , liftMStateT+ , (>~:>)+ , (>:>)+ )+where++import Control.Monad.State.Lazy+import Control.Monad.Identity++import Haskus.Utils.HArray++-- | Multi-state monad transformer+--+-- States are stacked in a heterogeneous array.+type MStateT (s :: [*]) m a = StateT (HArray s) m a++-- | Multi-state+type MState (s :: [*]) a = MStateT s Identity a++-- | Run MState+runMState :: MState s a -> HArray s -> (a,HArray s)+runMState act s = runIdentity (runStateT act s)++-- | Evaluate MState+evalMState :: MState s a -> HArray s -> a+evalMState act s = runIdentity (evalStateT act s)++-- | Execute MState+execMState :: MState s a -> HArray s -> HArray s+execMState act s = runIdentity (execStateT act s)++-- | Set a value in the state+mSet :: (Monad m, HArrayIndexT a s) => a -> MStateT s m ()+mSet = modify' . setHArrayT++-- | Get a value in the state+mGet :: (Monad m, HArrayIndexT a s) => MStateT s m a+mGet = getHArrayT <$> get++-- | Try to get a value in the state+mTryGet :: (Monad m, HArrayTryIndexT a s) => MStateT s m (Maybe a)+mTryGet = tryGetHArrayT <$> get+++-- | Modify a value in the state+mModify :: (Monad m, HArrayIndexT a s) => (a -> a) -> MStateT s m ()+mModify f = modify (\s -> setHArrayT (f (getHArrayT s)) s)++-- | Modify a value in the state (strict version)+mModify' :: (Monad m, HArrayIndexT a s) => (a -> a) -> MStateT s m ()+mModify' f = modify' (\s -> setHArrayT (f (getHArrayT s)) s)++-- | Execute an action with an extended state+mWith :: forall s a m b.+ ( Monad m+ ) => a -> MStateT (a ': s) m b -> MStateT s m b+mWith v act = do+ s <- get+ (r,s') <- lift $ runStateT act (prependHArray v s)+ put (tailHArray s')+ return r++-- | Lift a multi-state into an HArray transformer+liftMStateT :: (Monad m) => MStateT xs m x -> HArrayT m xs (x ': xs)+liftMStateT act = HArrayT $ \xs -> do+ (x,xs') <- runStateT act xs+ return (prependHArray x xs')++-- | Compose MStateT+(>~:>) :: (Monad m) => HArrayT m xs ys -> MStateT ys m y -> HArrayT m xs (y ': ys)+(>~:>) f g = f >~:~> liftMStateT g++-- | Compose MStateT+(>:>) :: (Monad m) => MStateT xs m x -> MStateT (x ': xs) m y -> HArrayT m xs (y ': x ': xs)+(>:>) f g = liftMStateT f >~:~> liftMStateT g
+ src/lib/Haskus/Utils/Parser.hs view
@@ -0,0 +1,189 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE ExistentialQuantification #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE AllowAmbiguousTypes #-}++-- | Tools to write parsers using Flows+module Haskus.Utils.Parser+ ( ParseError (..)+ , Choice (..)+ , choice+ , choice'+ , manyBounded+ , manyAtMost+ , manyAtMost'+ , manyAtMost''+ , many+ , manyAtLeast+ , manyTill+ , manyTill'+ )+where++import Prelude hiding (min,max)+import Haskus.Utils.HList+import Haskus.Utils.Types.List+import Haskus.Utils.Flow+import Haskus.Utils.Variant+++-- A parser is a Flow function that can either:+-- - return a parsed value or a semantic error+-- - fail with a ParseError:+-- - not enough input+-- - syntax error+--++-- | Parser error+data ParseError+ = SyntaxError+ | EndOfInput+ deriving (Show,Eq)++-- We can define combinators between parsers++data Choice a = Choice++instance forall x y z xs ys zs m a.+ ( x ~ Flow m xs+ , y ~ Flow m ys+ , z ~ Flow m zs+ , Catchable a xs+ , Liftable ys zs+ , Liftable (Filter a xs) zs+ , zs ~ Union (Filter a xs) ys+ , Monad m+ ) => Apply (Choice a) (x,y) z+ where+ apply _ (x,y) = x >%~|> \(_ :: a) -> y++-- | Try to apply the actions in the list in order, until one of them succeeds.+-- Returns the value of the succeeding action, or the value of the last one.+-- Failures are detected with values of type "ParseError".+choice :: forall m fs zs.+ ( Monad m+ , HFoldl (Choice ParseError) (Flow m '[ParseError]) fs (Flow m zs)+ ) => HList fs -> Flow m zs+choice = choice' @ParseError++-- | Try to apply the actions in the list in order, until one of them succeeds.+-- Returns the value of the succeeding action, or the value of the last one.+-- Failures are detected with values of type "a".+choice' :: forall a m fs zs.+ ( Monad m+ , HFoldl (Choice a) (Flow m '[a]) fs (Flow m zs)+ ) => HList fs -> Flow m zs+choice' = hFoldl (Choice :: Choice a) (flowSingle undefined :: Flow m '[a])++-- | Apply the action zero or more times (until a ParseError result is+-- returned)+many ::+ ( zs ~ Filter ParseError xs+ , Monad m+ , Catchable ParseError xs+ ) => Flow m xs -> Flow m '[[Variant zs]]+many f = manyBounded Nothing Nothing f+ >%~^> \(_ :: ParseError) -> flowSingle []++-- | Apply the action zero or more times (up to max) until a ParseError result+-- is returned+manyAtMost ::+ ( zs ~ Filter ParseError xs+ , Monad m+ , Catchable ParseError xs+ ) => Word -> Flow m xs -> Flow m '[[Variant zs]]+manyAtMost max f = manyBounded Nothing (Just max) f+ >%~^> \(_ :: ParseError) -> flowSingle []++-- | Apply the action zero or more times (up to max) until a ParseError result+-- is returned+manyAtMost' ::+ ( zs ~ Filter ParseError xs+ , Monad m+ , Catchable ParseError xs+ ) => Word -> Flow m xs -> m [Variant zs]+manyAtMost' max f = singleVariant <$> manyAtMost max f++-- | Apply the action zero or more times (up to max) until a ParseError result+-- is returned+manyAtMost'' ::+ ( '[x] ~ Filter ParseError xs+ , Monad m+ , Catchable ParseError xs+ ) => Word -> Flow m xs -> m [x]+manyAtMost'' max f = fmap singleVariant <$> manyAtMost' max f++-- | Apply the action at least n times or more times (until a ParseError+-- result is returned)+manyAtLeast ::+ ( zs ~ Filter ParseError xs+ , Monad m+ , Catchable ParseError xs+ ) => Word -> Flow m xs -> Flow m '[[Variant zs],ParseError]+manyAtLeast min = manyBounded (Just min) Nothing++-- | Apply the first action zero or more times until the second succeeds.+-- If the first action fails, the whole operation fails.+--+-- Return both the list of first values and the ending value+manyTill ::+ ( zs ~ Filter ParseError xs+ , zs' ~ Filter ParseError ys+ , Monad m+ , MaybeCatchable ParseError xs+ , Catchable ParseError ys+ ) => Flow m xs -> Flow m ys -> Flow m '[([Variant zs],Variant zs'),ParseError]+manyTill f g = go []+ where+ go xs = do+ v <- g+ case catchVariant v of+ Right EndOfInput -> flowSet EndOfInput+ Right SyntaxError -> do+ u <- f+ case catchVariantMaybe u of+ Right (e :: ParseError) -> flowSet e+ Left x -> go (x:xs)+ Left x -> flowSet (reverse xs,x)++-- | Apply the first action zero or more times until the second succeeds.+-- If the first action fails, the whole operation fails.+--+-- Return only the list of first values+manyTill' ::+ ( zs ~ Filter ParseError xs+ , Monad m+ , MaybeCatchable ParseError xs+ , Catchable ParseError ys+ ) => Flow m xs -> Flow m ys -> Flow m '[[Variant zs],ParseError]+manyTill' f g = manyTill f g >.-.> fst++-- | Apply the given action at least 'min' times and at most 'max' time+--+-- On failure, fails.+manyBounded :: forall zs xs m.+ ( zs ~ Filter ParseError xs+ , Monad m+ , MaybeCatchable ParseError xs+ ) => Maybe Word -> Maybe Word -> Flow m xs -> Flow m '[[Variant zs],ParseError]+manyBounded _ (Just 0) _ = flowSet ([] :: [Variant zs])+manyBounded (Just 0) max f = manyBounded Nothing max f+manyBounded min max f = do+ v <- f+ case catchVariantMaybe v of+ Right (e :: ParseError) -> case min of+ Just n | n > 0 -> flowSet e+ _ -> flowSet ([] :: [Variant zs])+ Left x -> do+ let minus1 = fmap (\k -> k - 1)+ xs <- manyBounded (minus1 min) (minus1 max) f+ case toEither xs of+ Left (e :: ParseError) -> flowSet e+ Right xs' -> flowSet (x : xs')+
+ src/lib/Haskus/Utils/STM.hs view
@@ -0,0 +1,61 @@+-- | STM helpers+module Haskus.Utils.STM+ ( S.STM+ , S.retry+ , atomically+ -- ** TVar+ , S.TVar+ , newTVarIO+ , readTVarIO+ , S.writeTVar+ , S.readTVar+ , S.newTVar+ , S.swapTVar+ , S.modifyTVar+ , S.modifyTVar'+ -- ** TMVar+ , S.TMVar+ , newTMVarIO+ , S.isEmptyTMVar+ , S.newEmptyTMVar+ , S.newEmptyTMVarIO+ , S.readTMVar+ , S.takeTMVar+ , S.putTMVar+ , S.swapTMVar+ , S.tryReadTMVar+ , S.tryPutTMVar+ , S.tryTakeTMVar+ -- ** TChan+ , S.TChan+ , newBroadcastTChanIO+ , S.newBroadcastTChan+ , S.writeTChan+ , S.dupTChan+ , S.readTChan+ )+where++import Control.Concurrent.STM (STM, TVar, TMVar, TChan)+import qualified Control.Concurrent.STM as S+import Haskus.Utils.Monad++-- | Execute an STM transaction atomically+atomically :: MonadIO m => STM a -> m a+atomically = liftIO . S.atomically++-- | Read a TVar in an IO monad+readTVarIO :: MonadIO m => TVar a -> m a+readTVarIO = liftIO . S.readTVarIO++-- | Create a broadcast channel+newBroadcastTChanIO :: MonadIO m => m (TChan a)+newBroadcastTChanIO = liftIO S.newBroadcastTChanIO++-- | Create a TVar+newTVarIO :: MonadIO m => a -> m (TVar a)+newTVarIO = liftIO . S.newTVarIO++-- | Create a TMVar+newTMVarIO :: MonadIO m => a -> m (TMVar a)+newTMVarIO = liftIO . S.newTMVarIO
+ src/lib/Haskus/Utils/STM/Future.hs view
@@ -0,0 +1,59 @@+-- | Future values (values that can only be set once)+module Haskus.Utils.STM.Future+ ( Future+ , FutureSource+ , newFuture+ , newFutureIO+ , waitFuture+ , pollFuture+ , pollFutureIO+ , setFuture+ , setFutureIO+ , setFuture'+ )+where++import Haskus.Utils.STM+import Haskus.Utils.Flow++-- | Future value of type a+newtype Future a = Future (TMVar a)++-- | Setter for a future value+newtype FutureSource a = FutureSource (TMVar a)++-- | Create a Future and its source+newFuture :: STM (Future a, FutureSource a)+newFuture = do+ m <- newEmptyTMVar+ return (Future m, FutureSource m)++-- | `newFuture` in `IO`+newFutureIO :: MonadIO m => m (Future a, FutureSource a)+newFutureIO = atomically newFuture++-- | Set a future+setFuture :: a -> FutureSource a -> STM ()+setFuture a m = void (setFuture' a m)++-- | Set a future in IO+setFutureIO :: MonadIO m => a -> FutureSource a -> m ()+setFutureIO a m = atomically (setFuture a m)++-- | Set a future+--+-- Return False if it has already been set+setFuture' :: a -> FutureSource a -> STM Bool+setFuture' a (FutureSource m) = tryPutTMVar m a++-- | Wait for a future+waitFuture :: Future a -> STM a+waitFuture (Future m) = readTMVar m++-- | Poll a future+pollFuture :: Future a -> STM (Maybe a)+pollFuture (Future m) = tryReadTMVar m++-- | `pollFuture` in `IO`+pollFutureIO :: MonadIO m => Future a -> m (Maybe a)+pollFutureIO = atomically . pollFuture
+ src/lib/Haskus/Utils/STM/TEq.hs view
@@ -0,0 +1,17 @@+-- | Equality in a STM context+module Haskus.Utils.STM.TEq+ ( TEq (..)+ )+where++import Haskus.Utils.STM++class TEq a where+ teq :: a -> a -> STM Bool+++instance Eq a => TEq (TVar a) where+ teq a b = do+ a' <- readTVar a+ b' <- readTVar b+ return (a' == b')
+ src/lib/Haskus/Utils/STM/TGraph.hs view
@@ -0,0 +1,85 @@+-- | Transactionnal graph+module Haskus.Utils.STM.TGraph+ ( deepFirst+ , breadthFirst+ , TNode (..)+ , singleton+ , linkTo+ )+where++import qualified Data.Set as Set++import Haskus.Utils.STM+import Haskus.Utils.Flow+import Haskus.Utils.STM.TList (TList)+import qualified Haskus.Utils.STM.TList as TList++-- | Deep-first graph traversal+--+-- before is executed when the node is entered+-- after is executed when the node is leaved+-- children gets node's children+--+deepFirst :: (Monad m, Ord a) => (a -> m ()) -> (a -> m ()) -> (a -> m [a]) -> [a] -> m ()+deepFirst before after children = foldM_ go Set.empty+ where+ go visited x + | Set.member x visited = + -- the node is already visited+ return visited++ | otherwise = do+ before x+ cs <- children x+ -- add current node to the visited ones to avoid "loops"+ let visited' = Set.insert x visited+ -- visited "children" nodes+ visited'' <- foldM go visited' cs+ after x+ return visited''++-- | Breadth-first graph traversal+--+-- visit is executed when the node is entered. If False is returned, the traversal ends+-- children gets node's children+--+breadthFirst :: (Monad m, Ord a) => (a -> m Bool) -> (a -> m [a]) -> [a] -> m ()+breadthFirst visit children = go Set.empty+ where+ go _ [] = + -- there are no more nodes to visit+ return ()++ go visited (x:xs) + | Set.member x visited = + -- the node is already visited, we skip it+ go visited xs++ | otherwise = do+ b <- visit x+ -- if "visit" returns False, we stop the traversal+ when b $ do+ -- otherwise we add children to the list of nodes to+ -- visit and we continue the traversal+ cs <- children x+ go (Set.insert x visited) (xs ++ cs)+++-- | A node contains a value and two lists of incoming/outgoing edges+data TNode a r = TNode+ { nodeValue :: a+ , nodeEdgeIn :: TList (r, TNode a r)+ , nodeEdgeOut :: TList (r, TNode a r)+ }++-- | Create a graph node+singleton :: a -> STM (TNode a r)+singleton v = TNode v <$> TList.empty <*> TList.empty++-- | Link two nodes together+linkTo :: TNode a r -> r -> TNode a r -> STM ()+linkTo src rel dst = do+ void $ TList.append (rel, src) (nodeEdgeIn dst)+ void $ TList.append (rel, dst) (nodeEdgeOut src)+
+ src/lib/Haskus/Utils/STM/TList.hs view
@@ -0,0 +1,263 @@+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE LambdaCase #-}++-- | Transactional list+module Haskus.Utils.STM.TList+ ( TList+ , TNode+ , empty+ , singleton+ , null+ , length+ , first+ , last+ , prev+ , next+ , value+ , deleteAll+ , delete+ , filter+ , find+ , append+ , append_+ , prepend+ , prepend_+ , insertBefore+ , insertAfter+ , toList+ , toReverseList+ , fromList+ , index+ , take+ )+where++import Prelude hiding (null,length,last,filter,take)++import Haskus.Utils.STM+import Haskus.Utils.Flow+import Haskus.Utils.Maybe++-- | A double linked-list+newtype TList a = TList (TNode a)++-- | A node in the list+--+-- Every list has a marker node whose value is Nothing. Its nodePrev links to+-- the last node and its nodeNext links to the first node.+data TNode a = TNode+ { nodeValue :: Maybe a -- value (Nothing if list marker)+ , nodePrev :: TVar (TNode a) -- previous node+ , nodeNext :: TVar (TNode a) -- next node+ }++-- | Get value associated with a node+value :: TNode a -> a+value node = case nodeValue node of+ Just v -> v+ Nothing -> error "TList: empty node value"++-- | Empty node singleton+empty :: STM (TList a)+empty = do+ p <- newTVar undefined+ n <- newTVar undefined+ let node = TNode Nothing p n+ -- initially the marker node refers to itself+ writeTVar p node+ writeTVar n node+ return (TList node)++-- | Remove all the elements of the list (O(1))+deleteAll :: TList a -> STM ()+deleteAll (TList m) = do+ -- make the marker node refer to itself+ writeTVar (nodeNext m) m+ writeTVar (nodePrev m) m++-- | Create a singleton list+singleton :: e -> STM (TList e)+singleton e = do+ m <- empty+ void $ append e m+ return m++-- | Indicate if the list is empty+null :: TList e -> STM Bool+null (TList m) = do+ h <- readTVar (nodeNext m)+ -- if the list is empty, the marker node refers to itself, hence the value of+ -- the nodeNext node is Nothing+ return (isNothing (nodeValue h))++-- | Count the number of elements in the list (0(n))+length :: TList e -> STM Word+length (TList m) = go 0 m+ where+ go !n node = do+ node' <- readTVar (nodeNext node)+ case nodeValue node' of+ Nothing -> return n+ Just _ -> go (n+1) node'++-- | Get the first element if any+first :: TList e -> STM (Maybe (TNode e))+first (TList m) = next m++-- | Get the last element if any+last :: TList e -> STM (Maybe (TNode e))+last (TList m) = prev m++-- | Get the previous element if any+prev :: TNode a -> STM (Maybe (TNode a))+prev n = do+ h <- readTVar (nodePrev n)+ case nodeValue h of+ Nothing -> return Nothing+ Just _ -> return (Just h)++-- | Get the next element if any+next :: TNode a -> STM (Maybe (TNode a))+next n = do+ h <- readTVar (nodeNext n)+ case nodeValue h of+ Nothing -> return Nothing+ Just _ -> return (Just h)+++-- | Delete a element of the list+delete :: TNode a -> STM ()+delete n = do+ -- if somehow we delete the marker node, we get a ring-list+ left <- readTVar $ nodePrev n+ right <- readTVar $ nodeNext n+ writeTVar (nodeNext left) right+ writeTVar (nodePrev right) left+ -- Link list node to itself so subsequent 'delete' calls will be harmless.+ writeTVar (nodePrev n) n+ writeTVar (nodeNext n) n++-- | Insert a node between two adjacent nodes.+insertBetween :: a -> TNode a -> TNode a -> STM (TNode a)+insertBetween v left right = do+ n <- TNode (Just v) <$> newTVar left + <*> newTVar right+ writeTVar (nodeNext left) n+ writeTVar (nodePrev right) n+ return n++-- | Append an element to the list+append :: a -> TList a -> STM (TNode a)+append v (TList m) = insertAfter v m++-- | Append an element to the list+append_ :: a -> TList a -> STM ()+append_ a = void . append a++-- | Prepend an element to the list+prepend :: a -> TList a -> STM (TNode a)+prepend v (TList m) = insertBefore v m++-- | Prepend an element to the list+prepend_ :: a -> TList a -> STM ()+prepend_ a = void . prepend a++-- | Insert an element before another+insertBefore :: a -> TNode a -> STM (TNode a)+insertBefore v n = do+ right <- readTVar $ nodeNext n+ insertBetween v n right++-- | Insert an element after another+insertAfter :: a -> TNode a -> STM (TNode a)+insertAfter v n = do+ left <- readTVar $ nodePrev n+ insertBetween v left n++-- | Convert into a list (O(n))+toList :: TList a -> STM [a]+toList (TList m) = go [] m+ where+ go !xs node = do+ node' <- readTVar (nodePrev node)+ case nodeValue node' of+ Nothing -> return xs+ Just x -> go (x:xs) node'++-- | Convert into a reversed list (O(n))+toReverseList :: TList a -> STM [a]+toReverseList (TList m) = go [] m+ where+ go !xs node = do+ node' <- readTVar (nodeNext node)+ case nodeValue node' of+ Nothing -> return xs+ Just x -> go (x:xs) node'++-- | Create from a list+fromList :: [e] -> STM (TList e)+fromList xs = do+ s <- empty+ forM_ xs (`append` s)+ return s++-- | Only keep element matching the criterium+filter :: (e -> STM Bool) -> TList e -> STM ()+filter f (TList m) = go m+ where+ go node = do+ node' <- readTVar (nodeNext node)+ case nodeValue node' of+ Nothing -> return ()+ Just v -> do+ p <- f v+ if not p+ then delete node' >> go node+ else go node'++-- | Find the first node matching the predicate (if any)+find :: (e -> STM Bool) -> TList e -> STM (Maybe (TNode e))+find f (TList m) = go m+ where+ go node = do+ node' <- readTVar (nodeNext node)+ case nodeValue node' of+ Nothing -> return Nothing+ Just v -> do+ p <- f v+ if p+ then return (Just node')+ else go node'++-- | Get the node from its index+index :: Word -> TList e -> STM (Maybe (TNode e))+index n (TList m) = go n m+ where+ go !i node = do+ node' <- readTVar (nodeNext node)+ case nodeValue node' of+ Nothing -> return Nothing+ Just _+ | i == 0 -> return (Just node')+ | otherwise -> go (i-1) node'++-- | Take (and remove) up to n elements in the list (O(n))+take :: Word -> TList e -> STM [e]+take n l = index n l >>= \case+ -- return the whole list+ Nothing -> do+ r <- toList l+ deleteAll l+ return r++ -- build the list and remove elements at the same time+ Just node -> go [] node+ where+ go !xs node' = do+ case nodeValue node' of+ Nothing -> return xs+ Just x -> do+ p <- readTVar (nodePrev node')+ delete node'+ go (x:xs) p
+ src/lib/Haskus/Utils/STM/TMap.hs view
@@ -0,0 +1,98 @@+{-# LANGUAGE ConstraintKinds #-}++-- | STm hashmap+module Haskus.Utils.STM.TMap+ ( TMap+ , Key+ , null+ , size+ , lookup+ , member+ , notMember+ , empty+ , singleton+ , insert+ , fromList+ , delete+ , elems+ , keys+ , (!)+ )+where++import Prelude hiding (lookup,null)++import Haskus.Utils.STM+import qualified STMContainers.Map as SMAP+import STMContainers.Map (Key)+import ListT (fold)+import qualified ListT++import Haskus.Utils.Maybe (fromJust,isJust,isNothing)++-- | STM hashmap+type TMap a b = SMAP.Map a b++-- | Indicate if the map is empty+null :: TMap a b -> STM Bool+null = SMAP.null++-- | Get the number of elements in the map+size :: TMap a b -> STM Int+size = fold f 0 . SMAP.stream+ where + f n _ = return (n+1)++-- | Lookup an element in the map from its key+lookup :: Key k => k -> TMap k a -> STM (Maybe a)+lookup = SMAP.lookup++-- | Check if a key is in the map+member :: Key k => k -> TMap k b -> STM Bool+member k m = isJust <$> lookup k m++-- | Check if a key is not in the map+notMember :: Key k => k -> TMap k b -> STM Bool+notMember k m = isNothing <$> lookup k m++-- | Create an empty map+empty :: STM (TMap a b)+empty = SMAP.new++-- | Create a map containing a single element+singleton :: Key k => k -> v -> STM (TMap k v)+singleton k v = do+ m <- empty+ insert k v m+ return m++-- | Insert an element in the map+insert :: Key k => k -> v -> TMap k v -> STM ()+insert k v = SMAP.insert v k++-- | Create a new TMap from a list+fromList :: Key k => [(k,v)] -> STM (TMap k v)+fromList vs = do+ m <- empty+ mapM_ (\(k,v) -> insert k v m) vs+ return m++-- | Delete an element from the map+delete :: Key k => k -> TMap k v -> STM ()+delete = SMAP.delete++-- | Create a list of (key,value)+toList :: TMap a b -> STM [(a,b)]+toList = ListT.toList . SMAP.stream++-- | Get values+elems :: TMap a b -> STM [b]+elems = fmap (fmap snd) . toList++-- | Get keys+keys :: TMap a b -> STM [a]+keys = fmap (fmap fst) . toList++-- | Unsafe lookup in the map+(!) :: Key k => TMap k v -> k -> STM v+(!) m k = fromJust <$> lookup k m
+ src/lib/Haskus/Utils/STM/TSet.hs view
@@ -0,0 +1,108 @@+{-# LANGUAGE ConstraintKinds #-}++-- | STM mutable set+module Haskus.Utils.STM.TSet+ ( TSet+ , null+ , size+ , member+ , notMember+ , empty+ , singleton+ , insert+ , delete+ , toList+ , fromList+ , elems+ , stream+ , unions+ , map+ )+where++import Prelude hiding (lookup,null,map)++import Haskus.Utils.STM+import qualified STMContainers.Set as SSET+import STMContainers.Set (Element)+import ListT (ListT, fold)+import qualified ListT++import Haskus.Utils.Flow (forM_)++-- | STM Set+type TSet a = SSET.Set a++-- | Indicate if the set is empty+null :: TSet a -> STM Bool+null = SSET.null++-- | Number of elements in the set+size :: TSet a -> STM Int+size = fold f 0 . SSET.stream+ where + f n _ = return (n+1)++-- | Check if an element is in the set+member :: Element e => e -> TSet e -> STM Bool+member = SSET.lookup++-- | Check if an element is not in the set+notMember :: Element e => e -> TSet e -> STM Bool+notMember e s = not <$> member e s++-- | Create an empty set+empty :: STM (TSet e)+empty = SSET.new++-- | Create a set containing a single element+singleton :: Element e => e -> STM (TSet e)+singleton e = do+ m <- empty+ insert e m+ return m++-- | Insert an element in a set+insert :: Element e => e -> TSet e -> STM ()+insert = SSET.insert++-- | Delete an element from a set+delete :: Element e => e -> TSet e -> STM ()+delete = SSET.delete++-- | Convert a set into a list+toList :: TSet e -> STM [e]+toList = ListT.toList . SSET.stream++-- | Create a set from a list+fromList :: Element e => [e] -> STM (TSet e)+fromList xs = do+ s <- empty+ forM_ xs (`insert` s)+ return s++-- | Get the set elements+elems :: TSet e -> STM [e]+elems = toList++-- | Get the set as a ListT stream+stream :: TSet e -> ListT STM e+stream = SSET.stream++-- | Perform a set union+unions :: Element e => [TSet e] -> STM (TSet e)+unions ss = do+ ret <- empty+ forM_ ss $ \s -> + ListT.traverse_ (`insert` ret) (stream s)+ return ret++-- | Apply a function to each element in the set+map :: (Element b) => (a -> b) -> TSet a -> STM (TSet b)+map f m = do+ r <- empty+ ListT.traverse_ (\x -> insert (f x) r) (stream m)+ return r++--filter :: (a -> Bool) -> TSet a -> STM ()+--filter f = withTVar (Set.filter f)
+ src/lib/Haskus/Utils/STM/TTree.hs view
@@ -0,0 +1,78 @@+-- | STM mutable tree+module Haskus.Utils.STM.TTree+ ( TTree (..)+ , TTreePath (..)+ , singleton+ , addChild+ , detachChild+ , attachChild+ , treeFollowPath+ )+where++import qualified Haskus.Utils.STM.TList as TList+import Haskus.Utils.STM.TList (TList)+import Haskus.Utils.STM.TEq+import Haskus.Utils.STM++-- | A STM mutable tree+data TTree k v = TTree+ { treeKey :: k -- ^ Node identifier+ , treeValue :: v -- ^ Node value+ , treeChildren :: TList (TTree k v) -- ^ Children+ , treeParent :: TVar (Maybe (TTree k v)) -- ^ Parent+ }++-- | Path in the tree+newtype TTreePath k = TTreePath [k]+++-- | Create a singleton node+singleton :: k -> v -> STM (TTree k v)+singleton k v =+ TTree k v+ <$> TList.empty+ <*> newTVar Nothing++-- | Add a child+addChild :: k -> v -> TTree k v -> STM (TTree k v)+addChild k v parent = do+ n <- TTree k v+ <$> TList.empty+ <*> newTVar (Just parent)++ TList.append_ n (treeChildren parent)+ return n++-- | Detach a child+detachChild :: TEq k => TTree k v -> STM ()+detachChild n = do+ + -- remove child from parent+ let f c = not <$> (treeKey c `teq` treeKey n)+ p <- readTVar (treeParent n)+ mapM_ (TList.filter f . treeChildren) p++ -- remove parent from child+ writeTVar (treeParent n) Nothing++-- | Attach a child a node (detaching it from a previous one if necessary)+attachChild :: TEq k => TTree k v -> TTree k v -> STM ()+attachChild newparent child = do+ -- detach from the previous parent (if any)+ detachChild child++ -- add to newparent's children list+ TList.append_ child (treeChildren newparent)++ -- set newparent+ writeTVar (treeParent child) (Just newparent)++-- | Follow a path from a parent node+treeFollowPath :: TEq k => TTree k v -> TTreePath k -> STM (Maybe (TTree k v))+treeFollowPath p (TTreePath []) = return (Just p)+treeFollowPath p (TTreePath (x:xs)) = do+ child <- TList.find (\y -> x `teq` treeKey y) (treeChildren p)+ case TList.value <$> child of+ Just c -> treeFollowPath c (TTreePath xs)+ Nothing -> return Nothing
+ src/lib/Haskus/Utils/Tuple.hs view
@@ -0,0 +1,496 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FunctionalDependencies #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeFamilies #-}++-- | Tuple helpers+module Haskus.Utils.Tuple+ ( uncurry4+ , take4+ , fromTuple4+ , module Data.Tuple+ , Single (..)+ , TupleToList+ , ListToTuple+ , ExtractTuple (..)+ , TupleHead (..)+ , TupleTail (..)+ , TupleCons (..)+ , ReorderTuple (..)+ )+where++import Data.Tuple+import Haskus.Utils.Types++-- | Uncurry specialised for quadruple+uncurry4 :: (a -> b -> c -> d -> e) -> (a,b,c,d) -> e+{-# INLINE uncurry4 #-}+uncurry4 f (a,b,c,d) = f a b c d+++-- | Take specialised for quadruple+take4 :: [a] -> (a,a,a,a)+{-# INLINE take4 #-}+take4 [a,b,c,d] = (a,b,c,d)+take4 _ = error "take4: invalid list (exactly 4 elements required)"+++-- | toList for quadruple+fromTuple4 :: (a,a,a,a) -> [a]+{-# INLINE fromTuple4 #-}+fromTuple4 (a,b,c,d) = [a,b,c,d]++-- | Singleton type+newtype Single a = Single a deriving (Show,Eq)+++type family TupleToList t where+ TupleToList (Single a) = '[a]+ TupleToList (a,b) = '[a,b]+ TupleToList (a,b,c) = '[a,b,c]+ TupleToList (a,b,c,d) = '[a,b,c,d]+ TupleToList (a,b,c,d,e) = '[a,b,c,d,e]+ TupleToList (a,b,c,d,e,f) = '[a,b,c,d,e,f]+ TupleToList (a,b,c,d,e,f,g) = '[a,b,c,d,e,f,g]+ TupleToList (a,b,c,d,e,f,g,h) = '[a,b,c,d,e,f,g,h]+ TupleToList (a,b,c,d,e,f,g,h,i) = '[a,b,c,d,e,f,g,h,i]+ TupleToList (a,b,c,d,e,f,g,h,i,j) = '[a,b,c,d,e,f,g,h,i,j]+ TupleToList (a,b,c,d,e,f,g,h,i,j,k) = '[a,b,c,d,e,f,g,h,i,j,k]+ TupleToList (a,b,c,d,e,f,g,h,i,j,k,l) = '[a,b,c,d,e,f,g,h,i,j,k,l]+ TupleToList (a,b,c,d,e,f,g,h,i,j,k,l,m) = '[a,b,c,d,e,f,g,h,i,j,k,l,m]+ TupleToList (a,b,c,d,e,f,g,h,i,j,k,l,m,n) = '[a,b,c,d,e,f,g,h,i,j,k,l,m,n]+ TupleToList (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o) = '[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o]+ TupleToList (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) = '[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p]+ TupleToList (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q) = '[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q]+ TupleToList (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r) = '[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r]+ TupleToList (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s) = '[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s]+ TupleToList (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t) = '[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t]+ TupleToList (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u) = '[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u]+ TupleToList (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v) = '[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v]+ TupleToList (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w) = '[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w]+ TupleToList (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x) = '[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x]+ TupleToList (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y) = '[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y]+ TupleToList (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z) = '[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z]++type family ListToTuple t where+ ListToTuple '[a] = Single a+ ListToTuple '[a,b] = (a,b)+ ListToTuple '[a,b,c] = (a,b,c)+ ListToTuple '[a,b,c,d] = (a,b,c,d)+ ListToTuple '[a,b,c,d,e] = (a,b,c,d,e)+ ListToTuple '[a,b,c,d,e,f] = (a,b,c,d,e,f)+ ListToTuple '[a,b,c,d,e,f,g] = (a,b,c,d,e,f,g)+ ListToTuple '[a,b,c,d,e,f,g,h] = (a,b,c,d,e,f,g,h)+ ListToTuple '[a,b,c,d,e,f,g,h,i] = (a,b,c,d,e,f,g,h,i)+ ListToTuple '[a,b,c,d,e,f,g,h,i,j] = (a,b,c,d,e,f,g,h,i,j)+ ListToTuple '[a,b,c,d,e,f,g,h,i,j,k] = (a,b,c,d,e,f,g,h,i,j,k)+ ListToTuple '[a,b,c,d,e,f,g,h,i,j,k,l] = (a,b,c,d,e,f,g,h,i,j,k,l)+ ListToTuple '[a,b,c,d,e,f,g,h,i,j,k,l,m] = (a,b,c,d,e,f,g,h,i,j,k,l,m)+ ListToTuple '[a,b,c,d,e,f,g,h,i,j,k,l,m,n] = (a,b,c,d,e,f,g,h,i,j,k,l,m,n)+ ListToTuple '[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o] = (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o)+ ListToTuple '[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p] = (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p)+ ListToTuple '[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q] = (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q)+ ListToTuple '[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r] = (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r)+ ListToTuple '[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s] = (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s)+ ListToTuple '[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t] = (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t)+ ListToTuple '[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u] = (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u)+ ListToTuple '[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v] = (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v)+ ListToTuple '[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w] = (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w)+ ListToTuple '[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x] = (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x)+ ListToTuple '[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y] = (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y)+ ListToTuple '[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z] = (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z)++-- | Extract a tuple value statically+class ExtractTuple (n :: Nat) t x | n t -> x where+ -- | Extract a tuple value by type-level index+ tupleN :: t -> x++instance ExtractTuple 0 (Single t) t where+ {-# INLINE tupleN #-}+ tupleN (Single t) = t++instance ExtractTuple 0 (e0, e1) e0 where+ {-# INLINE tupleN #-}+ tupleN (t,_) = t++instance ExtractTuple 1 (e0, e1) e1 where+ {-# INLINE tupleN #-}+ tupleN (_,t) = t++instance ExtractTuple 0 (e0, e1, e2) e0 where+ {-# INLINE tupleN #-}+ tupleN (t,_,_) = t++instance ExtractTuple 1 (e0, e1, e2) e1 where+ {-# INLINE tupleN #-}+ tupleN (_,t,_) = t++instance ExtractTuple 2 (e0, e1, e2) e2 where+ {-# INLINE tupleN #-}+ tupleN (_,_,t) = t++instance ExtractTuple 0 (e0, e1, e2, e3) e0 where+ {-# INLINE tupleN #-}+ tupleN (t,_,_,_) = t++instance ExtractTuple 1 (e0, e1, e2, e3) e1 where+ {-# INLINE tupleN #-}+ tupleN (_,t,_,_) = t++instance ExtractTuple 2 (e0, e1, e2, e3) e2 where+ {-# INLINE tupleN #-}+ tupleN (_,_,t,_) = t++instance ExtractTuple 3 (e0, e1, e2, e3) e3 where+ {-# INLINE tupleN #-}+ tupleN (_,_,_,t) = t+++instance ExtractTuple 0 (e0, e1, e2, e3, e4) e0 where+ {-# INLINE tupleN #-}+ tupleN (t,_,_,_,_) = t++instance ExtractTuple 1 (e0, e1, e2, e3, e4) e1 where+ {-# INLINE tupleN #-}+ tupleN (_,t,_,_,_) = t++instance ExtractTuple 2 (e0, e1, e2, e3, e4) e2 where+ {-# INLINE tupleN #-}+ tupleN (_,_,t,_,_) = t++instance ExtractTuple 3 (e0, e1, e2, e3, e4) e3 where+ {-# INLINE tupleN #-}+ tupleN (_,_,_,t,_) = t++instance ExtractTuple 4 (e0, e1, e2, e3, e4) e4 where+ {-# INLINE tupleN #-}+ tupleN (_,_,_,_,t) = t+++instance ExtractTuple 0 (e0, e1, e2, e3, e4, e5) e0 where+ {-# INLINE tupleN #-}+ tupleN (t,_,_,_,_,_) = t++instance ExtractTuple 1 (e0, e1, e2, e3, e4, e5) e1 where+ {-# INLINE tupleN #-}+ tupleN (_,t,_,_,_,_) = t++instance ExtractTuple 2 (e0, e1, e2, e3, e4, e5) e2 where+ {-# INLINE tupleN #-}+ tupleN (_,_,t,_,_,_) = t++instance ExtractTuple 3 (e0, e1, e2, e3, e4, e5) e3 where+ {-# INLINE tupleN #-}+ tupleN (_,_,_,t,_,_) = t++instance ExtractTuple 4 (e0, e1, e2, e3, e4, e5) e4 where+ {-# INLINE tupleN #-}+ tupleN (_,_,_,_,t,_) = t++instance ExtractTuple 5 (e0, e1, e2, e3, e4, e5) e5 where+ {-# INLINE tupleN #-}+ tupleN (_,_,_,_,_,t) = t+++instance ExtractTuple 0 (e0, e1, e2, e3, e4, e5, e6) e0 where+ {-# INLINE tupleN #-}+ tupleN (t,_,_,_,_,_,_) = t++instance ExtractTuple 1 (e0, e1, e2, e3, e4, e5, e6) e1 where+ {-# INLINE tupleN #-}+ tupleN (_,t,_,_,_,_,_) = t++instance ExtractTuple 2 (e0, e1, e2, e3, e4, e5, e6) e2 where+ {-# INLINE tupleN #-}+ tupleN (_,_,t,_,_,_,_) = t++instance ExtractTuple 3 (e0, e1, e2, e3, e4, e5, e6) e3 where+ {-# INLINE tupleN #-}+ tupleN (_,_,_,t,_,_,_) = t++instance ExtractTuple 4 (e0, e1, e2, e3, e4, e5, e6) e4 where+ {-# INLINE tupleN #-}+ tupleN (_,_,_,_,t,_,_) = t++instance ExtractTuple 5 (e0, e1, e2, e3, e4, e5, e6) e5 where+ {-# INLINE tupleN #-}+ tupleN (_,_,_,_,_,t,_) = t++instance ExtractTuple 6 (e0, e1, e2, e3, e4, e5, e6) e6 where+ {-# INLINE tupleN #-}+ tupleN (_,_,_,_,_,_,t) = t+++instance ExtractTuple 0 (e0, e1, e2, e3, e4, e5, e6, e7) e0 where+ {-# INLINE tupleN #-}+ tupleN (t,_,_,_,_,_,_,_) = t++instance ExtractTuple 1 (e0, e1, e2, e3, e4, e5, e6, e7) e1 where+ {-# INLINE tupleN #-}+ tupleN (_,t,_,_,_,_,_,_) = t++instance ExtractTuple 2 (e0, e1, e2, e3, e4, e5, e6, e7) e2 where+ {-# INLINE tupleN #-}+ tupleN (_,_,t,_,_,_,_,_) = t++instance ExtractTuple 3 (e0, e1, e2, e3, e4, e5, e6, e7) e3 where+ {-# INLINE tupleN #-}+ tupleN (_,_,_,t,_,_,_,_) = t++instance ExtractTuple 4 (e0, e1, e2, e3, e4, e5, e6, e7) e4 where+ {-# INLINE tupleN #-}+ tupleN (_,_,_,_,t,_,_,_) = t++instance ExtractTuple 5 (e0, e1, e2, e3, e4, e5, e6, e7) e5 where+ {-# INLINE tupleN #-}+ tupleN (_,_,_,_,_,t,_,_) = t++instance ExtractTuple 6 (e0, e1, e2, e3, e4, e5, e6, e7) e6 where+ {-# INLINE tupleN #-}+ tupleN (_,_,_,_,_,_,t,_) = t++instance ExtractTuple 7 (e0, e1, e2, e3, e4, e5, e6, e7) e7 where+ {-# INLINE tupleN #-}+ tupleN (_,_,_,_,_,_,_,t) = t+++class TupleHead ts ts' | ts -> ts' where+ tupleHead :: ts -> ts'++instance TupleHead (Single a) a where+ {-# INLINE tupleHead #-}+ tupleHead (Single a) = a++instance TupleHead (a,b) a where+ {-# INLINE tupleHead #-}+ tupleHead (a,_) = a++instance TupleHead (a,b,c) a where+ {-# INLINE tupleHead #-}+ tupleHead (a,_,_) = a++instance TupleHead (a,b,c,d) a where+ {-# INLINE tupleHead #-}+ tupleHead (a,_,_,_) = a++instance TupleHead (a,b,c,d,e) a where+ {-# INLINE tupleHead #-}+ tupleHead (a,_,_,_,_) = a++instance TupleHead (a,b,c,d,e,f) a where+ {-# INLINE tupleHead #-}+ tupleHead (a,_,_,_,_,_) = a+++class TupleTail ts ts' | ts -> ts' where+ tupleTail :: ts -> ts'++instance TupleTail (a,b) (Single b) where+ {-# INLINE tupleTail #-}+ tupleTail (_,b) = Single b++instance TupleTail (a,b,c) (b,c) where+ {-# INLINE tupleTail #-}+ tupleTail (_,b,c) = (b,c)++instance TupleTail (a,b,c,d) (b,c,d) where+ {-# INLINE tupleTail #-}+ tupleTail (_,b,c,d) = (b,c,d)++instance TupleTail (a,b,c,d,e) (b,c,d,e) where+ {-# INLINE tupleTail #-}+ tupleTail (_,b,c,d,e) = (b,c,d,e)++instance TupleTail (a,b,c,d,e,f) (b,c,d,e,f) where+ {-# INLINE tupleTail #-}+ tupleTail (_,b,c,d,e,f) = (b,c,d,e,f)++++class TupleCons t ts ts' | t ts -> ts' where+ tupleCons :: t -> ts -> ts'++instance TupleCons a (Single b) (a,b) where+ {-# INLINE tupleCons #-}+ tupleCons a (Single b) = (a,b)++instance TupleCons a (b,c) (a,b,c) where+ {-# INLINE tupleCons #-}+ tupleCons a (b,c) = (a,b,c)++instance TupleCons a (b,c,d) (a,b,c,d) where+ {-# INLINE tupleCons #-}+ tupleCons a (b,c,d) = (a,b,c,d)++instance TupleCons a (b,c,d,e) (a,b,c,d,e) where+ {-# INLINE tupleCons #-}+ tupleCons a (b,c,d,e) = (a,b,c,d,e)++instance TupleCons a (b,c,d,e,f) (a,b,c,d,e,f) where+ {-# INLINE tupleCons #-}+ tupleCons a (b,c,d,e,f) = (a,b,c,d,e,f)+++-- | Reorder tuple elements+class ReorderTuple t1 t2 where+ -- | Reorder tuple elements+ tupleReorder :: t1 -> t2+++instance ReorderTuple (Single a) (Single a) where+ {-# INLINE tupleReorder #-}+ tupleReorder = id++instance ReorderTuple (a,b) (a,b) where+ {-# INLINE tupleReorder #-}+ tupleReorder = id++instance ReorderTuple (a,b,c) (a,b,c) where+ {-# INLINE tupleReorder #-}+ tupleReorder = id++instance ReorderTuple (a,b,c,d) (a,b,c,d) where+ {-# INLINE tupleReorder #-}+ tupleReorder = id++instance ReorderTuple (a,b,c,d,e) (a,b,c,d,e) where+ {-# INLINE tupleReorder #-}+ tupleReorder = id++instance ReorderTuple (a,b,c,d,e,f) (a,b,c,d,e,f) where+ {-# INLINE tupleReorder #-}+ tupleReorder = id++instance ReorderTuple (a,b,c,d,e,f,g) (a,b,c,d,e,f,g) where+ {-# INLINE tupleReorder #-}+ tupleReorder = id++instance ReorderTuple (a,b,c,d,e,f,g,h) (a,b,c,d,e,f,g,h) where+ {-# INLINE tupleReorder #-}+ tupleReorder = id++instance ReorderTuple (a,b,c,d,e,f,g,h,i) (a,b,c,d,e,f,g,h,i) where+ {-# INLINE tupleReorder #-}+ tupleReorder = id++instance ReorderTuple (a,b,c,d,e,f,g,h,i,j) (a,b,c,d,e,f,g,h,i,j) where+ {-# INLINE tupleReorder #-}+ tupleReorder = id+++instance ReorderTuple (a,b) (b,a) where+ {-# INLINE tupleReorder #-}+ tupleReorder (a,b) = (b,a)++instance ReorderTuple (a,b,c) (a,c,b) where+ {-# INLINE tupleReorder #-}+ tupleReorder (a,b,c) = (a,c,b)++instance ReorderTuple (a,b,c) (b,a,c) where+ {-# INLINE tupleReorder #-}+ tupleReorder (a,b,c) = (b,a,c)++instance ReorderTuple (a,b,c) (b,c,a) where+ {-# INLINE tupleReorder #-}+ tupleReorder (a,b,c) = (b,c,a)++instance ReorderTuple (a,b,c) (c,a,b) where+ {-# INLINE tupleReorder #-}+ tupleReorder (a,b,c) = (c,a,b)++instance ReorderTuple (a,b,c) (c,b,a) where+ {-# INLINE tupleReorder #-}+ tupleReorder (a,b,c) = (c,b,a)++instance ReorderTuple (b,c,d) (x,y,z) => ReorderTuple (a,b,c,d) (a,x,y,z) where+ {-# INLINE tupleReorder #-}+ tupleReorder (a,b,c,d) = let (x,y,z) = tupleReorder (b,c,d) in (a,x,y,z)++instance ReorderTuple (a,c,d) (x,y,z) => ReorderTuple (a,b,c,d) (x,b,y,z) where+ {-# INLINE tupleReorder #-}+ tupleReorder (a,b,c,d) = let (x,y,z) = tupleReorder (a,c,d) in (x,b,y,z)++instance ReorderTuple (a,b,d) (x,y,z) => ReorderTuple (a,b,c,d) (x,y,c,z) where+ {-# INLINE tupleReorder #-}+ tupleReorder (a,b,c,d) = let (x,y,z) = tupleReorder (a,b,d) in (x,y,c,z)++instance ReorderTuple (a,b,c) (x,y,z) => ReorderTuple (a,b,c,d) (x,y,z,d) where+ {-# INLINE tupleReorder #-}+ tupleReorder (a,b,c,d) = let (x,y,z) = tupleReorder (a,b,c) in (x,y,z,d)++instance ReorderTuple (b,c,d,e) (x,y,z,w) => ReorderTuple (a,b,c,d,e) (a,x,y,z,w) where+ {-# INLINE tupleReorder #-}+ tupleReorder (a,b,c,d,e) = let (x,y,z,w) = tupleReorder (b,c,d,e) in (a,x,y,z,w)++instance ReorderTuple (a,c,d,e) (x,y,z,w) => ReorderTuple (a,b,c,d,e) (x,b,y,z,w) where+ {-# INLINE tupleReorder #-}+ tupleReorder (a,b,c,d,e) = let (x,y,z,w) = tupleReorder (a,c,d,e) in (x,b,y,z,w)++instance ReorderTuple (a,b,d,e) (x,y,z,w) => ReorderTuple (a,b,c,d,e) (x,y,c,z,w) where+ {-# INLINE tupleReorder #-}+ tupleReorder (a,b,c,d,e) = let (x,y,z,w) = tupleReorder (a,b,d,e) in (x,y,c,z,w)++instance ReorderTuple (a,b,c,e) (x,y,z,w) => ReorderTuple (a,b,c,d,e) (x,y,z,d,w) where+ {-# INLINE tupleReorder #-}+ tupleReorder (a,b,c,d,e) = let (x,y,z,w) = tupleReorder (a,b,c,e) in (x,y,z,d,w)++instance ReorderTuple (a,b,c,d) (x,y,z,w) => ReorderTuple (a,b,c,d,e) (x,y,z,w,e) where+ {-# INLINE tupleReorder #-}+ tupleReorder (a,b,c,d,e) = let (x,y,z,w) = tupleReorder (a,b,c,d) in (x,y,z,w,e)++instance ReorderTuple (b,c,d,e,f) (x,y,z,w,v) => ReorderTuple (a,b,c,d,e,f) (a,x,y,z,w,v) where+ {-# INLINE tupleReorder #-}+ tupleReorder (a,b,c,d,e,f) = let (x,y,z,w,v) = tupleReorder (b,c,d,e,f) in (a,x,y,z,w,v)++instance ReorderTuple (a,c,d,e,f) (x,y,z,w,v) => ReorderTuple (a,b,c,d,e,f) (x,b,y,z,w,v) where+ {-# INLINE tupleReorder #-}+ tupleReorder (a,b,c,d,e,f) = let (x,y,z,w,v) = tupleReorder (a,c,d,e,f) in (x,b,y,z,w,v)++instance ReorderTuple (a,b,d,e,f) (x,y,z,w,v) => ReorderTuple (a,b,c,d,e,f) (x,y,c,z,w,v) where+ {-# INLINE tupleReorder #-}+ tupleReorder (a,b,c,d,e,f) = let (x,y,z,w,v) = tupleReorder (a,b,d,e,f) in (x,y,c,z,w,v)++instance ReorderTuple (a,b,c,e,f) (x,y,z,w,v) => ReorderTuple (a,b,c,d,e,f) (x,y,z,d,w,v) where+ {-# INLINE tupleReorder #-}+ tupleReorder (a,b,c,d,e,f) = let (x,y,z,w,v) = tupleReorder (a,b,c,e,f) in (x,y,z,d,w,v)++instance ReorderTuple (a,b,c,d,f) (x,y,z,w,v) => ReorderTuple (a,b,c,d,e,f) (x,y,z,w,e,v) where+ {-# INLINE tupleReorder #-}+ tupleReorder (a,b,c,d,e,f) = let (x,y,z,w,v) = tupleReorder (a,b,c,d,f) in (x,y,z,w,e,v)++instance ReorderTuple (a,b,c,d,e) (x,y,z,w,v) => ReorderTuple (a,b,c,d,e,f) (x,y,z,w,v,f) where+ {-# INLINE tupleReorder #-}+ tupleReorder (a,b,c,d,e,f) = let (x,y,z,w,v) = tupleReorder (a,b,c,d,e) in (x,y,z,w,v,f)+++instance ReorderTuple (b,c,d,e,f,g) (x,y,z,w,v,u) => ReorderTuple (a,b,c,d,e,f,g) (a,x,y,z,w,v,u) where+ {-# INLINE tupleReorder #-}+ tupleReorder (a,b,c,d,e,f,g) = let (x,y,z,w,v,u) = tupleReorder (b,c,d,e,f,g) in (a,x,y,z,w,v,u)++instance ReorderTuple (a,c,d,e,f,g) (x,y,z,w,v,u) => ReorderTuple (a,b,c,d,e,f,g) (x,b,y,z,w,v,u) where+ {-# INLINE tupleReorder #-}+ tupleReorder (a,b,c,d,e,f,g) = let (x,y,z,w,v,u) = tupleReorder (a,c,d,e,f,g) in (x,b,y,z,w,v,u)++instance ReorderTuple (a,b,d,e,f,g) (x,y,z,w,v,u) => ReorderTuple (a,b,c,d,e,f,g) (x,y,c,z,w,v,u) where+ {-# INLINE tupleReorder #-}+ tupleReorder (a,b,c,d,e,f,g) = let (x,y,z,w,v,u) = tupleReorder (a,b,d,e,f,g) in (x,y,c,z,w,v,u)++instance ReorderTuple (a,b,c,e,f,g) (x,y,z,w,v,u) => ReorderTuple (a,b,c,d,e,f,g) (x,y,z,d,w,v,u) where+ {-# INLINE tupleReorder #-}+ tupleReorder (a,b,c,d,e,f,g) = let (x,y,z,w,v,u) = tupleReorder (a,b,c,e,f,g) in (x,y,z,d,w,v,u)++instance ReorderTuple (a,b,c,d,f,g) (x,y,z,w,v,u) => ReorderTuple (a,b,c,d,e,f,g) (x,y,z,w,e,v,u) where+ {-# INLINE tupleReorder #-}+ tupleReorder (a,b,c,d,e,f,g) = let (x,y,z,w,v,u) = tupleReorder (a,b,c,d,f,g) in (x,y,z,w,e,v,u)++instance ReorderTuple (a,b,c,d,e,g) (x,y,z,w,v,u) => ReorderTuple (a,b,c,d,e,f,g) (x,y,z,w,v,f,u) where+ {-# INLINE tupleReorder #-}+ tupleReorder (a,b,c,d,e,f,g) = let (x,y,z,w,v,u) = tupleReorder (a,b,c,d,e,g) in (x,y,z,w,v,f,u)++instance ReorderTuple (a,b,c,d,e,f) (x,y,z,w,v,u) => ReorderTuple (a,b,c,d,e,f,g) (x,y,z,w,v,u,g) where+ {-# INLINE tupleReorder #-}+ tupleReorder (a,b,c,d,e,f,g) = let (x,y,z,w,v,u) = tupleReorder (a,b,c,d,e,f) in (x,y,z,w,v,u,g)
+ src/lib/Haskus/Utils/Types.hs view
@@ -0,0 +1,76 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE AllowAmbiguousTypes #-}++-- | Common type functions+module Haskus.Utils.Types+ ( Nat+ , Symbol+ , natValue+ , natValue'+ , symbolValue+ , KnownNat+ , KnownSymbol+ , CmpNat+ , CmpSymbol+ , type (<=?)+ , type (<=)+ , type (+)+ , type (-)+ , type (*)+ , type (^)+ , If+ , IfNat+ , Modulo+ , Same+ , Proxy (..)+ , TypeError+ , ErrorMessage (..)+ )+where++import GHC.TypeLits+import Data.Proxy++-- | Get a Nat value+natValue :: forall (n :: Nat) a. (KnownNat n, Num a) => a+{-# INLINE natValue #-}+natValue = fromIntegral (natVal (Proxy :: Proxy n))++-- | Get a Nat value+natValue' :: forall (n :: Nat). KnownNat n => Word+{-# INLINE natValue' #-}+natValue' = natValue @n++-- | Get a Symbol value+symbolValue :: forall (s :: Symbol). (KnownSymbol s) => String+{-# INLINE symbolValue #-}+symbolValue = symbolVal (Proxy :: Proxy s)++-- | If-then-else+type family If c t e where+ If 'True t e = t+ If 'False t e = e++-- | If-then-else+type family IfNat c (t :: Nat) (e :: Nat) where+ IfNat 'True t e = t+ IfNat 'False t e = e++-- | Modulo+type family Modulo (a :: Nat) (b :: Nat) where+ Modulo a b = Modulo' (a <=? b) a b++-- | Helper for Modulo+type family Modulo' c a b where+ Modulo' 'True a b = a+ Modulo' 'False a b = Modulo' ((a-b) <=? b) (a-b) b++-- | Type equality to Nat+type family Same a b :: Nat where+ Same a a = 1+ Same a b = 0
+ src/lib/Haskus/Utils/Types/Generics.hs view
@@ -0,0 +1,75 @@+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE UndecidableInstances #-}++-- | Generics+module Haskus.Utils.Types.Generics+ ( module GHC.Generics+ -- * Fields+ , Field+ , FieldType+ , LookupField+ , LookupFieldType+ -- * Data type fields+ , ExtractFields+ , ExtractFieldTypes+ )+where++import Haskus.Utils.Types.List+import Haskus.Utils.Types+import GHC.Generics++-- | Named field+data Field (name :: Symbol) (t :: *)++type family FieldType f where+ FieldType (Field name t) = t++type family LookupFieldType fs s where+ LookupFieldType fs s = FieldType (LookupField fs s)++type family LookupField (fs :: [*]) (s :: Symbol) where+ LookupField (Field name t ': fs) name = Field name t+ LookupField (Field name t ': fs) s = LookupField fs s+ LookupField '[] name =+ TypeError ('Text "Cannot find field with name: " ':<>: 'ShowType name)+++-- | Extract fields of a data type:+-- - require selector symbols+-- - only support data type with a single constructor+type family ExtractFields (a :: *) where+ ExtractFields a = ExtractFields' (Rep a)++type family ExtractFields' a where+ -- extract constructors+ ExtractFields' (D1 _ cs) = ExtractFields' cs++ -- extract selectors+ ExtractFields' (C1 _ ss) = ExtractFields' ss+ ExtractFields' (s1 :*: s2) = Concat (ExtractFields' s1) (ExtractFields' s2)++ -- extract field name and type from the selector+ ExtractFields' (S1 ('MetaSel ('Just name) _ _ _) (Rec0 t)) = '[Field name t]++++-- | Extract types of the fields of a data type+-- - only support data type with a single constructor+type family ExtractFieldTypes (a :: *) where+ ExtractFieldTypes a = ExtractFieldTypes' (Rep a)++type family ExtractFieldTypes' a where+ -- extract constructors+ ExtractFieldTypes' (D1 _ cs) = ExtractFieldTypes' cs++ -- extract selectors+ ExtractFieldTypes' (C1 _ ss) = ExtractFieldTypes' ss+ ExtractFieldTypes' (s1 :*: s2) =+ Concat (ExtractFieldTypes' s1) (ExtractFieldTypes' s2)++ -- extract field type from the selector+ ExtractFieldTypes' (S1 _ (Rec0 t)) = '[t]
+ src/lib/Haskus/Utils/Types/List.hs view
@@ -0,0 +1,276 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE FlexibleContexts #-}++-- | Utils for type lists+module Haskus.Utils.Types.List+ ( MapNat+ , Max+ , Tail+ , Drop+ , Take+ , Init+ , Head+ , Snoc+ , ReplaceAt+ , Replace+ , ReplaceN+ , Reverse+ , RemoveAt+ , RemoveAt1+ , Concat+ , Length+ , Replicate+ , MapMaybe+ , Generate+ , IsMember+ , IsSubset+ , Indexes+ , MapTest+ , Zip+ , Filter+ , Nub+ , NubHead+ , IndexOf+ , MaybeIndexOf+ , Index+ , Union+ , Member+ , CheckNub+ )+where++import Haskus.Utils.Types++-- | Map a type function returning a Nat+type family MapNat (f :: * -> Nat) (xs :: [*]) where+ MapNat f '[] = '[]+ MapNat f (x ': xs) = f x ': MapNat f xs++-- | Get the max of a list of Nats+type family Max (xs :: [Nat]) where+ Max (x ': xs) = Max' x xs++-- | Helper for Max+type family Max' (x :: Nat) (xs :: [Nat]) where+ Max' x '[] = x+ Max' x (a ': xs) = Max' (IfNat (x <=? a) a x) xs++-- | Tail of a list+type family Tail (xs :: [*]) where+ Tail (x ': xs) = xs++-- | Drop elements in a list+type family Drop (n :: Nat) (xs :: [*]) where+ Drop 0 xs = xs+ Drop n (x ': xs) = Drop (n-1) xs++-- | Take elements in a list+type family Take (n :: Nat) (xs :: [*]) where+ Take 0 xs = '[]+ Take n (x ': xs) = x ': (Take (n-1) xs)++-- | Init of a list+type family Init (xs :: [*]) where+ Init '[x] = '[]+ Init (x ': xs) = x ': (Init xs)++-- | Snoc+type family Snoc (xs :: [*]) x where+ Snoc '[] x = '[x]+ Snoc (y ': ys) x = y ': (Snoc ys x)++-- | Head of a list+type family Head (xs :: [*]) where+ Head (x ': xs) = x++-- | Concat two type lists+type family Concat (xs :: [*]) (ys :: [*]) where+ Concat '[] '[] = '[]+ Concat '[] ys = ys+ Concat (x ': xs) ys = x ': Concat xs ys++-- | Get list length+type family Length xs where+ Length '[] = 0+ Length (x ': xs) = 1 + Length xs++-- | Replicate+type family Replicate n s where+ Replicate 0 s = '[]+ Replicate n s = s ': Replicate (n-1) s++-- | replace l[n] with l2 (folded)+type family ReplaceAt (n :: Nat) l l2 where+ ReplaceAt 0 (x ': xs) ys = Concat ys xs+ ReplaceAt n (x ': xs) ys = x ': ReplaceAt (n-1) xs ys++-- | replace a type by another in l+type family Replace t1 t2 l where+ Replace t1 t2 '[] = '[]+ Replace t1 t2 (t1 ': xs) = t2 ': (Replace t1 t2 xs)+ Replace t1 t2 (x ': xs) = x ': (Replace t1 t2 xs)++-- | replace a type at offset n in l+type family ReplaceN n t l where+ ReplaceN 0 t (x ': xs) = (t ': xs)+ ReplaceN n t (x ': xs) = x ': ReplaceN (n-1) t xs++-- | Reverse a list+type family Reverse (l :: [*]) where+ Reverse l = ReverseEx l '[]++type family ReverseEx (l :: [*]) (l2 :: [*]) where+ ReverseEx '[] l = l+ ReverseEx (x ': xs) l = ReverseEx xs (x ': l)+++-- | Remove a type at index+type family RemoveAt (n :: Nat) l where+ RemoveAt 0 (x ': xs) = xs+ RemoveAt n (x ': xs) = x ': RemoveAt (n-1) xs++-- | Remove a type at index (0 == don't remove)+type family RemoveAt1 (n :: Nat) l where+ RemoveAt1 0 xs = xs+ RemoveAt1 1 (x ': xs) = xs+ RemoveAt1 n (x ': xs) = x ': RemoveAt1 (n-1) xs++-- | Apply Maybe to all the elements of the list+type family MapMaybe l where+ MapMaybe '[] = '[]+ MapMaybe (x ': xs) = Maybe x ': MapMaybe xs++-- | Generate a list of Nat [n..m-1]+type family Generate (n :: Nat) (m :: Nat) :: [Nat] where+ Generate n n = '[]+ Generate n m = n ': Generate (n+1) m++-- | Check that a type is member of a type list+type family IsMember a l :: Bool where+ IsMember a l = IsMemberEx a l l++-- | Check that a type is member of a type list+type family IsMemberEx a l (i :: [*]) :: Bool where+ IsMemberEx a (a ': l) i = 'True+ IsMemberEx a (b ': l) i = IsMemberEx a l i+ IsMemberEx a '[] i = TypeError ( 'Text "`"+ ':<>: 'ShowType a+ ':<>: 'Text "'"+ ':<>: 'Text " is not a member of "+ ':<>: 'ShowType i)+++-- | Check that a list is a subset of another+type family IsSubset l1 l2 :: Bool where+ IsSubset l1 l1 = 'True+ IsSubset l1 l2 = IsSubsetEx l1 l2 l2++-- | Helper for IsSubset+type family IsSubsetEx l1 l2 i :: Bool where+ IsSubsetEx '[] l2 i = 'True+ IsSubsetEx l1 '[] i = TypeError ( 'ShowType l1+ ':$$: 'Text "is not a subset of"+ ':$$: 'ShowType i)+ IsSubsetEx (x ': xs) (x ': ys) i = IsSubsetEx xs i i+ IsSubsetEx (x ': xs) (y ': ys) i = IsSubsetEx (x ': xs) ys i++-- | Get list indexes+type family Indexes (l :: [*]) where+ Indexes xs = IndexesFrom 0 xs++type family IndexesFrom (n :: Nat) (xs :: [*]) where+ IndexesFrom n '[] = '[]+ IndexesFrom n (x ': xs) = Proxy n ': IndexesFrom (n+1) xs++-- | Map to 1 if type equality, 0 otherwise+type family MapTest a (l :: [*]) where+ MapTest a '[] = '[]+ MapTest a (a ': xs) = Proxy 1 ': MapTest a xs+ MapTest a (x ': xs) = Proxy 0 ': MapTest a xs++-- | Zip two lists+type family Zip (l :: [*]) (l2 :: [*]) where+ Zip '[] xs = '[]+ Zip xs '[] = '[]+ Zip (x ': xs) (y ': ys) = (x,y) ': Zip xs ys++-- | Remove `a` in `l`+type family Filter a (l :: [*]) where+ Filter a '[] = '[]+ Filter a (a ': xs) = Filter a xs+ Filter a (x ': xs) = x ': Filter a xs++-- | Keep only a single value of each type+type family Nub (l :: [*]) where+ Nub '[] = '[]+ Nub (x ': xs) = x ': Nub (Filter x xs)++-- | Keep only a single value of the head type+type family NubHead (l :: [*]) where+ NubHead '[] = '[]+ NubHead (x ': xs) = x ': Filter x xs++-- | Get the first index of a type+type family IndexOf a (l :: [*]) :: Nat where+ IndexOf x xs = IndexOfEx x xs xs++-- | Get the first index of a type+type family IndexOfEx a (l :: [*]) (l2 :: [*]) :: Nat where+ IndexOfEx x (x ': xs) l2 = 0+ IndexOfEx y (x ': xs) l2 = 1 + IndexOfEx y xs l2+ IndexOfEx y '[] l2 = TypeError ( 'Text "`"+ ':<>: 'ShowType y+ ':<>: 'Text "'"+ ':<>: 'Text " is not a member of "+ ':<>: 'ShowType l2)+++-- | Get the first index (starting from 1) of a type or 0 if none+type family MaybeIndexOf a (l :: [*]) where+ MaybeIndexOf x xs = MaybeIndexOf' 0 x xs++-- | Helper for MaybeIndexOf+type family MaybeIndexOf' (n :: Nat) a (l :: [*]) where+ MaybeIndexOf' n x '[] = 0+ MaybeIndexOf' n x (x ': xs) = 1 + n+ MaybeIndexOf' n x (y ': xs) = MaybeIndexOf' (n+1) x xs++-- | Indexed access into the list+type family Index (n :: Nat) (l :: [*]) where+ Index 0 (x ': xs) = x+ Index n (x ': xs) = Index (n-1) xs++-- | Union two lists+type family Union (xs :: [*]) (ys :: [*]) where+ Union xs ys = Nub (Concat xs ys)++--------------------------------------+-- Constraints+--------------------------------------++-- | Constraint: x member of xs+type Member x xs =+ ( IsMember x xs ~ 'True+ , x ~ Index (IndexOf x xs) xs+ , KnownNat (IndexOf x xs)+ )++-- | Check that a list only contain a value of each type+type CheckNub (l :: [*]) =+ ( CheckNubEx l (Nub l) ~ 'True+ )++type family CheckNubEx (l1 :: [*]) (l2 :: [*]) where+ CheckNubEx l l = 'True+ CheckNubEx l1 l2 = TypeError+ ( 'Text "Type-list contains unallowed redundant types."+ ':$$: 'Text "Got: " ':<>: 'ShowType l1+ ':$$: 'Text "Expected: " ':<>: 'ShowType l2+ )+
+ src/lib/Haskus/Utils/Variant.hs view
@@ -0,0 +1,932 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE RoleAnnotations #-}+{-# LANGUAGE ConstraintKinds #-}++-- | Typed Variant type (union)+module Haskus.Utils.Variant+ ( Variant+ , variantIndex+ , getVariantN+ , setVariantN+ , updateVariantN+ , setVariant+ , getVariant+ , updateVariant+ , updateVariantM+ , updateVariantFold+ , updateVariantFoldN+ , updateVariantFoldM+ , variantToHList+ , variantToTuple+ , liftEither+ , liftEitherM+ , variantRemoveType+ , Member+ , Catchable+ , MaybeCatchable+ , Liftable+ , catchVariant+ , catchVariantMaybe+ , pickVariant+ , headVariant+ , singleVariant+ , appendVariant+ , prependVariant+ , liftVariant+ , liftVariantM+ , toEither+ , ContVariant (..)+ )+where++import Unsafe.Coerce+import GHC.Exts (Any)++import Haskus.Utils.Monad+import Haskus.Utils.Types+import Haskus.Utils.Tuple+import Haskus.Utils.HList+import Haskus.Utils.ContFlow+import Haskus.Utils.Types.List++-- | A variant contains a value whose type is at the given position in the type+-- list+data Variant (l :: [*]) = Variant {-# UNPACK #-} !Word Any++-- | Make GHC consider `l` as a representational parameter to make coercions+-- between Variant values unsafe+type role Variant representational++-- | Get Variant index+variantIndex :: Variant a -> Word+variantIndex (Variant n _) = n++instance Eq (Variant '[]) where+ (==) = error "Empty variant"++instance+ ( Eq (Variant xs)+ , Eq x+ ) => Eq (Variant (x ': xs))+ where+ {-# INLINE (==) #-}+ (==) v1@(Variant t1 _) v2@(Variant t2 _)+ | t1 /= t2 = False+ | otherwise = case (headVariant v1, headVariant v2) of+ (Right a, Right b) -> a == b+ (Left as, Left bs) -> as == bs+ _ -> False++instance Ord (Variant '[]) where+ compare = error "Empty variant"++instance+ ( Ord (Variant xs)+ , Ord x+ ) => Ord (Variant (x ': xs))+ where+ compare v1 v2 = case (headVariant v1, headVariant v2) of+ (Right a, Right b) -> compare a b+ (Left as, Left bs) -> compare as bs+ (Right _, Left _) -> LT+ (Left _, Right _) -> GT++instance Show (Variant '[]) where+ show = error "Empty variant"++instance+ ( Show (Variant xs)+ , Show x+ ) => Show (Variant (x ': xs))+ where+ show v = case headVariant v of+ Right x -> show x+ Left xs -> show xs++-- | Set the value with the given indexed type+setVariantN :: forall (n :: Nat) (l :: [*]).+ ( KnownNat n+ ) => Index n l -> Variant l+{-# INLINE setVariantN #-}+setVariantN a = Variant (natValue @n) (unsafeCoerce a)++-- | Get the value if it has the indexed type+getVariantN :: forall (n :: Nat) (l :: [*]).+ ( KnownNat n+ ) => Variant l -> Maybe (Index n l)+{-# INLINE getVariantN #-}+getVariantN (Variant t a) = do+ guard (t == natValue @n)+ return (unsafeCoerce a) -- we know it is the effective type++-- | Lift an Either into a Variant (reversed order by convention)+liftEither :: Either a b -> Variant '[b,a]+{-# INLINE liftEither #-}+liftEither (Left a) = setVariantN @1 a+liftEither (Right b) = setVariantN @0 b++-- | Lift an Either into a Variant (reversed order by convention)+liftEitherM :: (Monad m) => m (Either a b) -> m (Variant '[b,a])+liftEitherM = fmap liftEither++-- | Update a variant value+updateVariantN :: forall (n :: Nat) a b l.+ ( KnownNat n+ , a ~ Index n l+ ) => (a -> b) -> Variant l -> Variant (ReplaceN n b l)+{-# INLINE updateVariantN #-}+updateVariantN f v@(Variant t a) =+ case getVariantN @n v of+ Nothing -> Variant t a+ Just x -> Variant t (unsafeCoerce (f x))++-- | Update a variant value in a Monad+updateVariantM :: forall (n :: Nat) l l2 m .+ (KnownNat n, Monad m)+ => (Index n l -> m (Index n l2)) -> Variant l -> m (Variant l2)+{-# INLINE updateVariantM #-}+updateVariantM f v@(Variant t a) =+ case getVariantN @n v of+ Nothing -> return (Variant t a)+ Just x -> Variant t <$> unsafeCoerce (f x)++-- | Update a variant value with a variant and fold the result+updateVariantFoldN :: forall (n :: Nat) l l2 .+ ( KnownNat n+ , KnownNat (Length l2)+ ) => (Index n l -> Variant l2) -> Variant l -> Variant (ReplaceAt n l l2)+updateVariantFoldN f v@(Variant t a) =+ case getVariantN @n v of+ Nothing ->+ -- we need to adapt the tag if new valid tags (from l2) are added before+ if t < n+ then Variant t a+ else Variant (t+nl2-1) a++ Just x -> case f x of+ Variant t2 a2 -> Variant (t2+n) a2+ where+ n = natValue @n+ nl2 = natValue @(Length l2)++-- | Update a variant value with a variant and fold the result+updateVariantFold :: forall a (n :: Nat) l l2 .+ ( KnownNat n+ , KnownNat (Length l2)+ , n ~ IndexOf a l+ , a ~ Index n l+ ) => (a -> Variant l2) -> Variant l -> Variant (ReplaceAt n l l2)+updateVariantFold f v = updateVariantFoldN @n f v++-- | Update a variant value with a variant and fold the result+updateVariantFoldM :: forall (n :: Nat) m l l2.+ ( KnownNat n+ , KnownNat (Length l2)+ , Monad m+ ) => (Index n l -> m (Variant l2)) -> Variant l -> m (Variant (ReplaceAt n l l2))+updateVariantFoldM f v@(Variant t a) =+ case getVariantN @n v of+ Nothing ->+ -- we need to adapt the tag if new valid tags (from l2) are added before+ return $ if t < n+ then Variant t a+ else Variant (t+nl2-1) a++ Just x -> do+ y <- f x+ case y of+ Variant t2 a2 -> return (Variant (t2+n) a2)+ where+ n = natValue @n+ nl2 = natValue @(Length l2)+++class VariantToHList xs where+ -- | Convert a variant into a HList of Maybes+ variantToHList :: Variant xs -> HList (MapMaybe xs)++instance VariantToHList '[] where+ variantToHList _ = HNil++instance+ ( VariantToHList xs+ ) => VariantToHList (x ': xs)+ where+ variantToHList v@(Variant t a) =+ getVariantN @0 v `HCons` variantToHList v'+ where+ v' :: Variant xs+ v' = Variant (t-1) a+++class VariantRemoveType a xs where+ -- | Remove a type from a variant+ variantRemoveType :: Variant xs -> Either (Variant (Filter a xs)) a++instance VariantRemoveType a '[] where+ variantRemoveType _ = undefined++instance forall a xs n xs' y ys.+ ( VariantRemoveType a xs'+ , n ~ MaybeIndexOf a xs+ , xs' ~ RemoveAt1 n xs+ , Filter a xs' ~ Filter a xs+ , KnownNat n+ , xs ~ (y ': ys)+ ) => VariantRemoveType a (y ': ys)+ where+ {-# INLINE variantRemoveType #-}+ variantRemoveType (Variant t a)+ = case natValue' @n of+ 0 -> Left (Variant t a) -- no 'a' left in xs+ n | n-1 == t -> Right (unsafeCoerce a)+ | n-1 < t -> variantRemoveType @a @xs' (Variant (t-1) a)+ | otherwise -> Left (Variant t a)++-- | a is catchable in xs+type Catchable a xs =+ ( IsMember a xs ~ 'True+ , VariantRemoveType a xs+ )++-- | a may be catchable in xs+type MaybeCatchable a xs =+ ( VariantRemoveType a xs+ )++-- | Extract a type from a variant. Return either the value of this type or the+-- remaining variant+catchVariant :: forall a xs.+ ( Catchable a xs+ ) => Variant xs -> Either (Variant (Filter a xs)) a+catchVariant v = variantRemoveType @a v++-- | Extract a type from a variant. Return either the value of this type or the+-- remaining variant+catchVariantMaybe :: forall a xs.+ ( MaybeCatchable a xs+ ) => Variant xs -> Either (Variant (Filter a xs)) a+catchVariantMaybe v = variantRemoveType @a v++-- | Pick a variant value+pickVariant :: forall (n :: Nat) l. + ( KnownNat n+ ) => Variant l -> Either (Variant (RemoveAt n l)) (Index n l)+{-# INLINE pickVariant #-}+pickVariant v@(Variant t a) = case getVariantN @n v of+ Just x -> Right x+ Nothing -> Left $ if t > natValue @n+ then Variant (t-1) a+ else Variant t a++-- | Pick the head of a variant value+headVariant :: forall x xs. Variant (x ': xs) -> Either (Variant xs) x+{-# INLINE headVariant #-}+headVariant v@(Variant t a) = case getVariantN @0 v of+ Just x -> Right x+ Nothing -> Left $ Variant (t-1) a+++-- | Get variant possible values in a tuple of Maybe types+variantToTuple :: forall l t.+ ( VariantToHList l+ , HTuple' (MapMaybe l) t+ ) => Variant l -> t+variantToTuple = hToTuple' . variantToHList++-- | Retreive the last v+singleVariant :: Variant '[a] -> a+{-# INLINE singleVariant #-}+singleVariant (Variant _ a) = unsafeCoerce a+++-- | Extend a variant by appending other possible values+appendVariant :: forall (ys :: [*]) (xs :: [*]). Variant xs -> Variant (Concat xs ys)+{-# INLINE appendVariant #-}+appendVariant (Variant t a) = Variant t a++-- | Extend a variant by prepending other possible values+prependVariant :: forall (ys :: [*]) (xs :: [*]).+ ( KnownNat (Length ys)+ ) => Variant xs -> Variant (Concat ys xs)+{-# INLINE prependVariant #-}+prependVariant (Variant t a) = Variant (n+t) a+ where+ n = natValue @(Length ys)++-- | Set the first matching type of a Variant+setVariant :: forall a l.+ ( Member a l+ ) => a -> Variant l+{-# INLINE setVariant #-}+setVariant = setVariantN @(IndexOf a l)++-- | Set the first matching type of a Variant+getVariant :: forall a l.+ ( Member a l+ ) => Variant l -> Maybe a+{-# INLINE getVariant #-}+getVariant = getVariantN @(IndexOf a l)++-- | Update a variant value+updateVariant :: forall a b n l.+ ( Member a l+ , n ~ IndexOf a l+ ) => (a -> b) -> Variant l -> Variant (ReplaceN n b l)+{-# INLINE updateVariant #-}+updateVariant f v = updateVariantN @n f v+++-- | xs is liftable in ys+type Liftable xs ys =+ ( IsSubset xs ys ~ 'True+ , VariantLift xs ys+ )+++class VariantLift xs ys where+ liftVariant' :: Variant xs -> Variant ys++instance VariantLift '[] ys where+ liftVariant' = error "Lifting empty variant"++instance forall x xs ys.+ ( VariantLift xs ys+ , KnownNat (IndexOf x ys)+ ) => VariantLift (x ': xs) ys+ where+ {-# INLINE liftVariant' #-}+ liftVariant' v = case headVariant v of+ Right a -> Variant (natValue @(IndexOf x ys)) (unsafeCoerce a)+ Left v' -> liftVariant' v'+++-- | Lift a variant into another+--+-- Set values to the first matching type+liftVariant :: forall xs ys.+ ( Liftable xs ys+ ) => Variant xs -> Variant ys+{-# INLINE liftVariant #-}+liftVariant = liftVariant'++liftVariantM ::+ ( Liftable xs ys+ , Monad m+ ) => Variant xs -> m (Variant ys)+{-# INLINE liftVariantM #-}+liftVariantM = return . liftVariant+++-- | Convert a variant of two values in a Either+toEither :: forall a b. Variant '[a,b] -> Either b a+toEither (Variant 0 a) = Right (unsafeCoerce a)+toEither (Variant _ a) = Left (unsafeCoerce a)+++class ContVariant xs where+ -- | Convert a variant into a multi-continuation+ variantToCont :: Variant xs -> ContFlow xs r++ -- | Convert a variant into a multi-continuation+ variantToContM :: Monad m => m (Variant xs) -> ContFlow xs (m r)++ -- | Convert a multi-continuation into a Variant+ contToVariant :: ContFlow xs (Variant xs) -> Variant xs++ -- | Convert a multi-continuation into a Variant+ contToVariantM :: Monad m => ContFlow xs (m (Variant xs)) -> m (Variant xs)++instance ContVariant '[a] where+ {-# INLINE variantToCont #-}+ variantToCont (Variant _ a) = ContFlow $ \(Single f) ->+ f (unsafeCoerce a)++ {-# INLINE variantToContM #-}+ variantToContM act = ContFlow $ \(Single f) -> do+ Variant _ a <- act+ f (unsafeCoerce a)++ {-# INLINE contToVariant #-}+ contToVariant c = c >::>+ Single (setVariantN @0)++ {-# INLINE contToVariantM #-}+ contToVariantM c = c >::>+ Single (return . setVariantN @0)++instance ContVariant '[a,b] where+ {-# INLINE variantToCont #-}+ variantToCont (Variant t a) = ContFlow $ \(f1,f2) ->+ case t of+ 0 -> f1 (unsafeCoerce a)+ _ -> f2 (unsafeCoerce a)++ {-# INLINE variantToContM #-}+ variantToContM act = ContFlow $ \(f1,f2) -> do+ Variant t a <- act+ case t of+ 0 -> f1 (unsafeCoerce a)+ _ -> f2 (unsafeCoerce a)++ {-# INLINE contToVariant #-}+ contToVariant c = c >::>+ ( setVariantN @0+ , setVariantN @1+ )++ {-# INLINE contToVariantM #-}+ contToVariantM c = c >::>+ ( return . setVariantN @0+ , return . setVariantN @1+ )++instance ContVariant '[a,b,c] where+ {-# INLINE variantToCont #-}+ variantToCont (Variant t a) = ContFlow $ \(f1,f2,f3) ->+ case t of+ 0 -> f1 (unsafeCoerce a)+ 1 -> f2 (unsafeCoerce a)+ _ -> f3 (unsafeCoerce a)++ {-# INLINE variantToContM #-}+ variantToContM act = ContFlow $ \(f1,f2,f3) -> do+ Variant t a <- act+ case t of+ 0 -> f1 (unsafeCoerce a)+ 1 -> f2 (unsafeCoerce a)+ _ -> f3 (unsafeCoerce a)++ {-# INLINE contToVariant #-}+ contToVariant c = c >::>+ ( setVariantN @0+ , setVariantN @1+ , setVariantN @2+ )++ {-# INLINE contToVariantM #-}+ contToVariantM c = c >::>+ ( return . setVariantN @0+ , return . setVariantN @1+ , return . setVariantN @2+ )++instance ContVariant '[a,b,c,d] where+ {-# INLINE variantToCont #-}+ variantToCont (Variant t a) = ContFlow $ \(f1,f2,f3,f4) ->+ case t of+ 0 -> f1 (unsafeCoerce a)+ 1 -> f2 (unsafeCoerce a)+ 2 -> f3 (unsafeCoerce a)+ _ -> f4 (unsafeCoerce a)++ {-# INLINE variantToContM #-}+ variantToContM act = ContFlow $ \(f1,f2,f3,f4) -> do+ Variant t a <- act+ case t of+ 0 -> f1 (unsafeCoerce a)+ 1 -> f2 (unsafeCoerce a)+ 2 -> f3 (unsafeCoerce a)+ _ -> f4 (unsafeCoerce a)++ {-# INLINE contToVariant #-}+ contToVariant c = c >::>+ ( setVariantN @0+ , setVariantN @1+ , setVariantN @2+ , setVariantN @3+ )++ {-# INLINE contToVariantM #-}+ contToVariantM c = c >::>+ ( return . setVariantN @0+ , return . setVariantN @1+ , return . setVariantN @2+ , return . setVariantN @3+ )++instance ContVariant '[a,b,c,d,e] where+ {-# INLINE variantToCont #-}+ variantToCont (Variant t a) = ContFlow $ \(f1,f2,f3,f4,f5) ->+ case t of+ 0 -> f1 (unsafeCoerce a)+ 1 -> f2 (unsafeCoerce a)+ 2 -> f3 (unsafeCoerce a)+ 3 -> f4 (unsafeCoerce a)+ _ -> f5 (unsafeCoerce a)++ {-# INLINE variantToContM #-}+ variantToContM act = ContFlow $ \(f1,f2,f3,f4,f5) -> do+ Variant t a <- act+ case t of+ 0 -> f1 (unsafeCoerce a)+ 1 -> f2 (unsafeCoerce a)+ 2 -> f3 (unsafeCoerce a)+ 3 -> f4 (unsafeCoerce a)+ _ -> f5 (unsafeCoerce a)++ {-# INLINE contToVariant #-}+ contToVariant c = c >::>+ ( setVariantN @0+ , setVariantN @1+ , setVariantN @2+ , setVariantN @3+ , setVariantN @4+ )++ {-# INLINE contToVariantM #-}+ contToVariantM c = c >::>+ ( return . setVariantN @0+ , return . setVariantN @1+ , return . setVariantN @2+ , return . setVariantN @3+ , return . setVariantN @4+ )++instance ContVariant '[a,b,c,d,e,f] where+ {-# INLINE variantToCont #-}+ variantToCont (Variant t a) = ContFlow $ \(f1,f2,f3,f4,f5,f6) ->+ case t of+ 0 -> f1 (unsafeCoerce a)+ 1 -> f2 (unsafeCoerce a)+ 2 -> f3 (unsafeCoerce a)+ 3 -> f4 (unsafeCoerce a)+ 4 -> f5 (unsafeCoerce a)+ _ -> f6 (unsafeCoerce a)++ {-# INLINE variantToContM #-}+ variantToContM act = ContFlow $ \(f1,f2,f3,f4,f5,f6) -> do+ Variant t a <- act+ case t of+ 0 -> f1 (unsafeCoerce a)+ 1 -> f2 (unsafeCoerce a)+ 2 -> f3 (unsafeCoerce a)+ 3 -> f4 (unsafeCoerce a)+ 4 -> f5 (unsafeCoerce a)+ _ -> f6 (unsafeCoerce a)++ {-# INLINE contToVariant #-}+ contToVariant c = c >::>+ ( setVariantN @0+ , setVariantN @1+ , setVariantN @2+ , setVariantN @3+ , setVariantN @4+ , setVariantN @5+ )++ {-# INLINE contToVariantM #-}+ contToVariantM c = c >::>+ ( return . setVariantN @0+ , return . setVariantN @1+ , return . setVariantN @2+ , return . setVariantN @3+ , return . setVariantN @4+ , return . setVariantN @5+ )++instance ContVariant '[a,b,c,d,e,f,g] where+ {-# INLINE variantToCont #-}+ variantToCont (Variant t a) = ContFlow $ \(f1,f2,f3,f4,f5,f6,f7) ->+ case t of+ 0 -> f1 (unsafeCoerce a)+ 1 -> f2 (unsafeCoerce a)+ 2 -> f3 (unsafeCoerce a)+ 3 -> f4 (unsafeCoerce a)+ 4 -> f5 (unsafeCoerce a)+ 5 -> f6 (unsafeCoerce a)+ _ -> f7 (unsafeCoerce a)++ {-# INLINE variantToContM #-}+ variantToContM act = ContFlow $ \(f1,f2,f3,f4,f5,f6,f7) -> do+ Variant t a <- act+ case t of+ 0 -> f1 (unsafeCoerce a)+ 1 -> f2 (unsafeCoerce a)+ 2 -> f3 (unsafeCoerce a)+ 3 -> f4 (unsafeCoerce a)+ 4 -> f5 (unsafeCoerce a)+ 5 -> f6 (unsafeCoerce a)+ _ -> f7 (unsafeCoerce a)++ {-# INLINE contToVariant #-}+ contToVariant c = c >::>+ ( setVariantN @0+ , setVariantN @1+ , setVariantN @2+ , setVariantN @3+ , setVariantN @4+ , setVariantN @5+ , setVariantN @6+ )++ {-# INLINE contToVariantM #-}+ contToVariantM c = c >::>+ ( return . setVariantN @0+ , return . setVariantN @1+ , return . setVariantN @2+ , return . setVariantN @3+ , return . setVariantN @4+ , return . setVariantN @5+ , return . setVariantN @6+ )++instance ContVariant '[a,b,c,d,e,f,g,h] where+ {-# INLINE variantToCont #-}+ variantToCont (Variant t a) = ContFlow $ \(f1,f2,f3,f4,f5,f6,f7,f8) ->+ case t of+ 0 -> f1 (unsafeCoerce a)+ 1 -> f2 (unsafeCoerce a)+ 2 -> f3 (unsafeCoerce a)+ 3 -> f4 (unsafeCoerce a)+ 4 -> f5 (unsafeCoerce a)+ 5 -> f6 (unsafeCoerce a)+ 6 -> f7 (unsafeCoerce a)+ _ -> f8 (unsafeCoerce a)++ {-# INLINE variantToContM #-}+ variantToContM act = ContFlow $ \(f1,f2,f3,f4,f5,f6,f7,f8) -> do+ Variant t a <- act+ case t of+ 0 -> f1 (unsafeCoerce a)+ 1 -> f2 (unsafeCoerce a)+ 2 -> f3 (unsafeCoerce a)+ 3 -> f4 (unsafeCoerce a)+ 4 -> f5 (unsafeCoerce a)+ 5 -> f6 (unsafeCoerce a)+ 6 -> f7 (unsafeCoerce a)+ _ -> f8 (unsafeCoerce a)++ {-# INLINE contToVariant #-}+ contToVariant c = c >::>+ ( setVariantN @0+ , setVariantN @1+ , setVariantN @2+ , setVariantN @3+ , setVariantN @4+ , setVariantN @5+ , setVariantN @6+ , setVariantN @7+ )++ {-# INLINE contToVariantM #-}+ contToVariantM c = c >::>+ ( return . setVariantN @0+ , return . setVariantN @1+ , return . setVariantN @2+ , return . setVariantN @3+ , return . setVariantN @4+ , return . setVariantN @5+ , return . setVariantN @6+ , return . setVariantN @7+ )++instance ContVariant '[a,b,c,d,e,f,g,h,i] where+ {-# INLINE variantToCont #-}+ variantToCont (Variant t a) = ContFlow $ \(f1,f2,f3,f4,f5,f6,f7,f8,f9) ->+ case t of+ 0 -> f1 (unsafeCoerce a)+ 1 -> f2 (unsafeCoerce a)+ 2 -> f3 (unsafeCoerce a)+ 3 -> f4 (unsafeCoerce a)+ 4 -> f5 (unsafeCoerce a)+ 5 -> f6 (unsafeCoerce a)+ 6 -> f7 (unsafeCoerce a)+ 7 -> f8 (unsafeCoerce a)+ _ -> f9 (unsafeCoerce a)++ {-# INLINE variantToContM #-}+ variantToContM act = ContFlow $ \(f1,f2,f3,f4,f5,f6,f7,f8,f9) -> do+ Variant t a <- act+ case t of+ 0 -> f1 (unsafeCoerce a)+ 1 -> f2 (unsafeCoerce a)+ 2 -> f3 (unsafeCoerce a)+ 3 -> f4 (unsafeCoerce a)+ 4 -> f5 (unsafeCoerce a)+ 5 -> f6 (unsafeCoerce a)+ 6 -> f7 (unsafeCoerce a)+ 7 -> f8 (unsafeCoerce a)+ _ -> f9 (unsafeCoerce a)++ {-# INLINE contToVariant #-}+ contToVariant c = c >::>+ ( setVariantN @0+ , setVariantN @1+ , setVariantN @2+ , setVariantN @3+ , setVariantN @4+ , setVariantN @5+ , setVariantN @6+ , setVariantN @7+ , setVariantN @8+ )++ {-# INLINE contToVariantM #-}+ contToVariantM c = c >::>+ ( return . setVariantN @0+ , return . setVariantN @1+ , return . setVariantN @2+ , return . setVariantN @3+ , return . setVariantN @4+ , return . setVariantN @5+ , return . setVariantN @6+ , return . setVariantN @7+ , return . setVariantN @8+ )++instance ContVariant '[a,b,c,d,e,f,g,h,i,j] where+ {-# INLINE variantToCont #-}+ variantToCont (Variant t a) = ContFlow $ \(f1,f2,f3,f4,f5,f6,f7,f8,f9,f10) ->+ case t of+ 0 -> f1 (unsafeCoerce a)+ 1 -> f2 (unsafeCoerce a)+ 2 -> f3 (unsafeCoerce a)+ 3 -> f4 (unsafeCoerce a)+ 4 -> f5 (unsafeCoerce a)+ 5 -> f6 (unsafeCoerce a)+ 6 -> f7 (unsafeCoerce a)+ 7 -> f8 (unsafeCoerce a)+ 8 -> f9 (unsafeCoerce a)+ _ -> f10 (unsafeCoerce a)++ {-# INLINE variantToContM #-}+ variantToContM act = ContFlow $ \(f1,f2,f3,f4,f5,f6,f7,f8,f9,f10) -> do+ Variant t a <- act+ case t of+ 0 -> f1 (unsafeCoerce a)+ 1 -> f2 (unsafeCoerce a)+ 2 -> f3 (unsafeCoerce a)+ 3 -> f4 (unsafeCoerce a)+ 4 -> f5 (unsafeCoerce a)+ 5 -> f6 (unsafeCoerce a)+ 6 -> f7 (unsafeCoerce a)+ 7 -> f8 (unsafeCoerce a)+ 8 -> f9 (unsafeCoerce a)+ _ -> f10 (unsafeCoerce a)++ {-# INLINE contToVariant #-}+ contToVariant c = c >::>+ ( setVariantN @0+ , setVariantN @1+ , setVariantN @2+ , setVariantN @3+ , setVariantN @4+ , setVariantN @5+ , setVariantN @6+ , setVariantN @7+ , setVariantN @8+ , setVariantN @9+ )++ {-# INLINE contToVariantM #-}+ contToVariantM c = c >::>+ ( return . setVariantN @0+ , return . setVariantN @1+ , return . setVariantN @2+ , return . setVariantN @3+ , return . setVariantN @4+ , return . setVariantN @5+ , return . setVariantN @6+ , return . setVariantN @7+ , return . setVariantN @8+ , return . setVariantN @9+ )++instance ContVariant '[a,b,c,d,e,f,g,h,i,j,k] where+ {-# INLINE variantToCont #-}+ variantToCont (Variant t a) = ContFlow $ \(f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f11) ->+ case t of+ 0 -> f1 (unsafeCoerce a)+ 1 -> f2 (unsafeCoerce a)+ 2 -> f3 (unsafeCoerce a)+ 3 -> f4 (unsafeCoerce a)+ 4 -> f5 (unsafeCoerce a)+ 5 -> f6 (unsafeCoerce a)+ 6 -> f7 (unsafeCoerce a)+ 7 -> f8 (unsafeCoerce a)+ 8 -> f9 (unsafeCoerce a)+ 9 -> f10 (unsafeCoerce a)+ _ -> f11 (unsafeCoerce a)++ {-# INLINE variantToContM #-}+ variantToContM act = ContFlow $ \(f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f11) -> do+ Variant t a <- act+ case t of+ 0 -> f1 (unsafeCoerce a)+ 1 -> f2 (unsafeCoerce a)+ 2 -> f3 (unsafeCoerce a)+ 3 -> f4 (unsafeCoerce a)+ 4 -> f5 (unsafeCoerce a)+ 5 -> f6 (unsafeCoerce a)+ 6 -> f7 (unsafeCoerce a)+ 7 -> f8 (unsafeCoerce a)+ 8 -> f9 (unsafeCoerce a)+ 9 -> f10 (unsafeCoerce a)+ _ -> f11 (unsafeCoerce a)++ {-# INLINE contToVariant #-}+ contToVariant c = c >::>+ ( setVariantN @0+ , setVariantN @1+ , setVariantN @2+ , setVariantN @3+ , setVariantN @4+ , setVariantN @5+ , setVariantN @6+ , setVariantN @7+ , setVariantN @8+ , setVariantN @9+ , setVariantN @10+ )++ {-# INLINE contToVariantM #-}+ contToVariantM c = c >::>+ ( return . setVariantN @0+ , return . setVariantN @1+ , return . setVariantN @2+ , return . setVariantN @3+ , return . setVariantN @4+ , return . setVariantN @5+ , return . setVariantN @6+ , return . setVariantN @7+ , return . setVariantN @8+ , return . setVariantN @9+ , return . setVariantN @10+ )++instance ContVariant '[a,b,c,d,e,f,g,h,i,j,k,l] where+ {-# INLINE variantToCont #-}+ variantToCont (Variant t a) = ContFlow $ \(f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f11,f12) ->+ case t of+ 0 -> f1 (unsafeCoerce a)+ 1 -> f2 (unsafeCoerce a)+ 2 -> f3 (unsafeCoerce a)+ 3 -> f4 (unsafeCoerce a)+ 4 -> f5 (unsafeCoerce a)+ 5 -> f6 (unsafeCoerce a)+ 6 -> f7 (unsafeCoerce a)+ 7 -> f8 (unsafeCoerce a)+ 8 -> f9 (unsafeCoerce a)+ 9 -> f10 (unsafeCoerce a)+ 10 -> f11 (unsafeCoerce a)+ _ -> f12 (unsafeCoerce a)++ {-# INLINE variantToContM #-}+ variantToContM act = ContFlow $ \(f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f11,f12) -> do+ Variant t a <- act+ case t of+ 0 -> f1 (unsafeCoerce a)+ 1 -> f2 (unsafeCoerce a)+ 2 -> f3 (unsafeCoerce a)+ 3 -> f4 (unsafeCoerce a)+ 4 -> f5 (unsafeCoerce a)+ 5 -> f6 (unsafeCoerce a)+ 6 -> f7 (unsafeCoerce a)+ 7 -> f8 (unsafeCoerce a)+ 8 -> f9 (unsafeCoerce a)+ 9 -> f10 (unsafeCoerce a)+ 10 -> f11 (unsafeCoerce a)+ _ -> f12 (unsafeCoerce a)++ {-# INLINE contToVariant #-}+ contToVariant c = c >::>+ ( setVariantN @0+ , setVariantN @1+ , setVariantN @2+ , setVariantN @3+ , setVariantN @4+ , setVariantN @5+ , setVariantN @6+ , setVariantN @7+ , setVariantN @8+ , setVariantN @9+ , setVariantN @10+ , setVariantN @11+ )++ {-# INLINE contToVariantM #-}+ contToVariantM c = c >::>+ ( return . setVariantN @0+ , return . setVariantN @1+ , return . setVariantN @2+ , return . setVariantN @3+ , return . setVariantN @4+ , return . setVariantN @5+ , return . setVariantN @6+ , return . setVariantN @7+ , return . setVariantN @8+ , return . setVariantN @9+ , return . setVariantN @10+ , return . setVariantN @11+ )
+ src/tests/Haskus/Tests/Utils.hs view
@@ -0,0 +1,14 @@+module Haskus.Tests.Utils where++import Test.Tasty++import Haskus.Tests.Utils.HArray+import Haskus.Tests.Utils.Variant++testsUtils :: TestTree+testsUtils = testGroup "Utils"+ [ testsHArray+ , testsVariant+ ]++
+ src/tests/Haskus/Tests/Utils/HArray.hs view
@@ -0,0 +1,92 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE AllowAmbiguousTypes #-}++module Haskus.Tests.Utils.HArray+ ( testsHArray+ )+where++import Test.Tasty+import Test.Tasty.QuickCheck as QC++import Haskus.Utils.HArray++testsHArray :: TestTree+testsHArray = testGroup "HArray" $+ [ testGroup "Getters"+ [ testProperty "Get by index 0" (getHArrayN @0 arr1 == 10)+ , testProperty "Get by index 1" (getHArrayN @1 arr1 == "Hello")+ , testProperty "Get by index 2" (getHArrayN @2 arr1 == False)+ , testProperty "Get by type 0" (getHArrayT arr1 == (10 :: Int))+ , testProperty "Get by type 1" (getHArrayT arr1 == "Hello")+ , testProperty "Get by type 2" (getHArrayT arr1 == False)+ ]+ , testGroup "Setters"+ [ testProperty "Set by index 0" (testSetGetN @0 20 arr1)+ , testProperty "Set by index 1" (testSetGetN @1 "World" arr1)+ , testProperty "Set by index 2" (testSetGetN @2 True arr1)+ , testProperty "Set by type 0" (testSetGetT (20 :: Int) arr1)+ , testProperty "Set by type 1" (testSetGetT "World" arr1)+ , testProperty "Set by type 2" (testSetGetT True arr1)+ ]+ , testGroup "Concat"+ [ testProperty "Get by type 0" (getHArrayT arr12 == (10 :: Int))+ , testProperty "Get by type 1" (getHArrayT arr12 == "Hello")+ , testProperty "Get by type 2" (getHArrayT arr12 == False)+ , testProperty "Get by type 3" (getHArrayT arr12 == (2.5 :: Double))+ , testProperty "Get by type 4" (getHArrayT arr12 == 'E')+ , testProperty "Get by type 0" (getHArrayT arr21 == (10 :: Int))+ , testProperty "Get by type 1" (getHArrayT arr21 == "Hello")+ , testProperty "Get by type 2" (getHArrayT arr21 == False)+ , testProperty "Get by type 3" (getHArrayT arr21 == (2.5 :: Double))+ , testProperty "Get by type 4" (getHArrayT arr21 == 'E')+ , testProperty "Get by index 0" (getHArrayN @0 arr12 == 10)+ , testProperty "Get by index 1" (getHArrayN @1 arr12 == "Hello")+ , testProperty "Get by index 2" (getHArrayN @2 arr12 == False)+ , testProperty "Get by index 3" (getHArrayN @3 arr12 == 2.5)+ , testProperty "Get by index 4" (getHArrayN @4 arr12 == 'E')+ , testProperty "Get by index 0" (getHArrayN @0 arr21 == 2.5)+ , testProperty "Get by index 1" (getHArrayN @1 arr21 == 'E')+ , testProperty "Get by index 2" (getHArrayN @2 arr21 == 10)+ , testProperty "Get by index 3" (getHArrayN @3 arr21 == "Hello")+ , testProperty "Get by index 4" (getHArrayN @4 arr21 == False)+ ]+ , testGroup "TryGetHArray"+ [ testProperty "Try get by type valid" (tryGetHArrayT arr1 == Just "Hello")+ , testProperty "Try get by type invalid" (tryGetHArrayT arr1 == (Nothing :: Maybe Char))+ ]+ ]+++arr1 :: HArray '[Int,String,Bool]+arr1 = prependHArray 10+ $ prependHArray "Hello"+ $ prependHArray False+ $ emptyHArray++testSetGetN :: forall n t ts.+ ( Eq t+ , HArrayIndex n t ts+ ) => t -> HArray ts -> Bool+testSetGetN a as = getHArrayN @n (setHArrayN @n a as) == a++testSetGetT ::+ ( Eq t+ , HArrayIndexT t ts+ ) => t -> HArray ts -> Bool+testSetGetT a as = getHArrayT (setHArrayT a as) == a++arr2 :: HArray '[Double,Char]+arr2 = prependHArray 2.5+ $ prependHArray 'E'+ $ emptyHArray++arr12 :: HArray '[Int,String,Bool,Double,Char]+arr12 = concatHArray arr1 arr2++arr21 :: HArray '[Double,Char,Int,String,Bool]+arr21 = concatHArray arr2 arr1
+ src/tests/Haskus/Tests/Utils/Variant.hs view
@@ -0,0 +1,111 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeApplications #-}++module Haskus.Tests.Utils.Variant+ ( testsVariant+ )+where++import Test.Tasty+import Test.Tasty.QuickCheck as QC+import Data.Either++import Haskus.Utils.Variant++data A = A deriving (Show,Eq)+data B = B deriving (Show,Eq)+data C = C deriving (Show,Eq)+data D = D deriving (Show,Eq)+data E = E deriving (Show,Eq)+data F = F deriving (Show,Eq)++type ABC = Variant '[A,B,C]+type DEF = Variant '[D,E,F]++b :: ABC+b = setVariantN @1 B++b2d :: B -> D+b2d = const D++c2d :: C -> D+c2d = const D++b2def :: B -> DEF+b2def = const (setVariant E)++c2def :: C -> DEF+c2def = const (setVariant E)+++testsVariant :: TestTree+testsVariant = testGroup "Variant" $+ [ testProperty "set/get by index (match)"+ (getVariantN @1 b == Just B)+ , testProperty "set/get by index (dont' match)"+ (getVariantN @0 b == Nothing)+ , testProperty "set/get by type (match)"+ (getVariant (setVariant B :: ABC) == Just B)+ , testProperty "set/get by type (don't match)"+ (getVariant @C (setVariant B :: ABC) == Nothing)++ , testProperty "variant equality (match)"+ (b == b)+ , testProperty "variant equality (don't match)"+ (b /= setVariant C)++ , testProperty "update by index (match)"+ (updateVariantN @1 (const D) b == setVariantN @1 D)+ , testProperty "update by index (don't match)"+ (updateVariantN @0 (const F) b == setVariantN @1 B)+ , testProperty "update by type (match)"+ (updateVariant b2d b == setVariantN @1 D)+ , testProperty "update by type (don't match)"+ (updateVariant c2d b == setVariant B)+ , testProperty "update/fold by index (match)"+ (updateVariantFoldN @1 b2def b == setVariant E)+ , testProperty "update/fold by index (don't match)"+ (updateVariantFoldN @2 c2def b == setVariant B)++ , testProperty "Convert into tuple"+ (variantToTuple b == (Nothing, Just B, Nothing))+ , testProperty "Convert single variant"+ (singleVariant (setVariant A :: Variant '[A]) == A)++ , testProperty "Lift Either: Left"+ (liftEither (Left A :: Either A B) == setVariant A)+ , testProperty "Lift Either: Right"+ (liftEither (Right B :: Either A B) == setVariant B)++ , testProperty "To Either: Left"+ (toEither (setVariant B :: Variant '[A,B]) == Left B)+ , testProperty "To Either: Right"+ (toEither (setVariant A :: Variant '[A,B]) == Right A)++ , testProperty "headVariant (match)"+ (headVariant (setVariant A :: ABC) == Right A)+ , testProperty "headVariant (don't match)"+ (isLeft (headVariant b))++ , testProperty "pickVariant (match)"+ (pickVariant @1 b == Right B)+ , testProperty "pickVariant (don't match)"+ (isLeft (pickVariant @2 b))++ , testProperty "catchVariant (match)"+ (catchVariant @D (setVariantN @4 D :: Variant '[A,B,C,B,D,E,D]) == Right D)+ , testProperty "catchVariant (match)"+ (catchVariant @D (setVariantN @6 D :: Variant '[A,B,C,B,D,E,D]) == Right D)+ , testProperty "catchVariant (don't match)"+ (catchVariant @B (setVariantN @4 D :: Variant '[A,B,C,B,D,E,D]) == Left (setVariantN @2 D))++ , testProperty "prependVariant"+ (getVariantN @4 (prependVariant @'[D,E,F] b) == Just B)+ , testProperty "appendVariant"+ (getVariantN @1 (appendVariant @'[D,E,F] b) == Just B)++ , testProperty "liftVariant"+ (getVariant (liftVariant b :: Variant '[D,A,E,B,F,C]) == Just B)+ ]
+ src/tests/Main.hs view
@@ -0,0 +1,5 @@+import Haskus.Tests.Utils+import Test.Tasty++main :: IO ()+main = defaultMain testsUtils