sized-wrapper (empty) → 0.1.0.0
raw patch · 5 files changed
+567/−0 lines, 5 filesdep +basedep +hspecdep +hspec-core
Dependencies added: base, hspec, hspec-core, hspec-discover, sized-wrapper
Files
- LICENSE +15/−0
- sized-wrapper.cabal +86/−0
- src/Data/Sized.hs +366/−0
- test/Data/SizedSpec.hs +99/−0
- test/Spec.hs +1/−0
+ LICENSE view
@@ -0,0 +1,15 @@+ISC License++Copyright (c) 2022 Gautier DI FOLCO++Permission to use, copy, modify, and/or distribute this software for any+purpose with or without fee is hereby granted, provided that the above+copyright notice and this permission notice appear in all copies.++THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY+AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR+OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR+PERFORMANCE OF THIS SOFTWARE.
+ sized-wrapper.cabal view
@@ -0,0 +1,86 @@+cabal-version: 3.0+name: sized-wrapper+version: 0.1.0.0+author: Gautier DI FOLCO+maintainer: gautier.difolco@gmail.com+category: Data+build-type: Simple+license: ISC+license-file: LICENSE+synopsis: Create a Sized version of any container+description: Create a Sized version of any container.+Homepage: http://github.com/blackheaven/sized-wrapper/sized-wrapper+tested-with: GHC==9.2.2, GHC==9.0.2, GHC==8.10.7++library+ default-language: Haskell2010+ build-depends:+ base == 4.*+ hs-source-dirs: src+ exposed-modules:+ Data.Sized+ other-modules:+ Paths_sized_wrapper+ autogen-modules:+ Paths_sized_wrapper+ default-extensions:+ DataKinds+ DefaultSignatures+ DeriveAnyClass+ DeriveGeneric+ DerivingStrategies+ DerivingVia+ DuplicateRecordFields+ FlexibleContexts+ GADTs+ GeneralizedNewtypeDeriving+ KindSignatures+ LambdaCase+ OverloadedLists+ OverloadedStrings+ RankNTypes+ RecordWildCards+ ScopedTypeVariables+ TypeApplications+ TypeFamilies+ TypeOperators+ ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wpartial-fields -Wredundant-constraints++test-suite sized-wrapper-test+ type: exitcode-stdio-1.0+ hs-source-dirs: test+ main-is: Spec.hs+ other-modules:+ Data.SizedSpec+ Paths_sized_wrapper+ autogen-modules:+ Paths_sized_wrapper+ default-extensions:+ DataKinds+ DefaultSignatures+ DeriveAnyClass+ DeriveGeneric+ DerivingStrategies+ DerivingVia+ DuplicateRecordFields+ FlexibleContexts+ GADTs+ GeneralizedNewtypeDeriving+ KindSignatures+ LambdaCase+ OverloadedLists+ OverloadedStrings+ RankNTypes+ RecordWildCards+ ScopedTypeVariables+ TypeApplications+ TypeFamilies+ TypeOperators+ ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wpartial-fields -Wredundant-constraints+ build-depends:+ base+ , sized-wrapper+ , hspec+ , hspec-core+ , hspec-discover+ default-language: Haskell2010
+ src/Data/Sized.hs view
@@ -0,0 +1,366 @@+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE UndecidableInstances #-}+{-# OPTIONS_GHC -Wno-redundant-constraints #-}++-- |+-- Module : Data.Sized+-- Copyright : Gautier DI FOLCO+-- License : BSD2+--+-- Maintainer : Gautier DI FOLCO <gautier.difolco@gmail.com>+-- Stability : Unstable+-- Portability : GHC+--+-- Create Sized version of any container.+module Data.Sized+ ( -- * Base type+ Sized,+ getSized,+ trustedSized,+ unknownSized,+ Unknown,+ Between,+ Exactly,+ AtLeast,+ AtMost,++ -- * Singleton constructor+ SizedSingleton (..),+ singleton,+ MkSizedSingletonApplicative (..),++ -- * From container+ Size (..),+ SizedFromContainer (..),+ MkSizedFromContainerFoldable (..),++ -- * Operations+ overSized,+ overSized2,+ overSized3,+ overSized4,+ overSized5,+ trustedChangeOverSized,+ trustedChangeOverSized2,+ trustedChangeOverSized3,+ trustedChangeOverSized4,+ trustedChangeOverSized5,+ fmapSized,+ withSized,+ precise,+ approximate,+ (<<>>),+ withSizedAppend,+ withSizedRetract,+ withSizedSubtract,+ withSizedProduct,++ -- * Type-level+ IsMoreGeneral,+ IsNotEmpty,+ type (<+>),+ RestrictAtMost,+ type (<->),+ type (<*>),+ Includes,+ )+where++import Data.Foldable (toList)+import Data.Ix (inRange)+import Data.Kind+import Data.Maybe (fromJust)+import Data.Proxy+import GHC.TypeLits as TypeLits++-- | Sized proofed value.+newtype Sized s a = Sized+ { -- | Extract the Sized proven value+ getSized :: a+ }+ deriving stock (Eq, Ord, Show)++-- * Different kind of sizes++-- | Unknown/any size+data Unknown++-- | Exactly 'n'+data Exactly (n :: Nat)++-- | At least 'n'+data AtLeast (n :: Nat)++-- | At most 'n'+data AtMost (n :: Nat)++-- | Between (included) '(n..m)'+data Between (n :: Nat) (m :: Nat)++-- * Operations++-- | Wrap and unwrap 'Sized' (unsafe, be sure 'f' is size-conservative)+overSized :: (a -> b) -> Sized s a -> Sized s b+overSized f = trustedSized . f . getSized+{-# INLINE overSized #-}++-- | Wrap and unwrap 'Sized' (unsafe, be sure 'f' is size-conservative)+overSized2 :: (a -> b -> c) -> Sized s a -> Sized s b -> Sized s c+overSized2 f a = trustedSized . f (getSized a) . getSized+{-# INLINE overSized2 #-}++-- | Wrap and unwrap 'Sized' (unsafe, be sure 'f' is size-conservative)+overSized3 :: (a -> b -> c -> d) -> Sized s a -> Sized s b -> Sized s c -> Sized s d+overSized3 f a b = trustedSized . f (getSized a) (getSized b) . getSized+{-# INLINE overSized3 #-}++-- | Wrap and unwrap 'Sized' (unsafe, be sure 'f' is size-conservative)+overSized4 :: (a -> b -> c -> d -> e) -> Sized s a -> Sized s b -> Sized s c -> Sized s d -> Sized s e+overSized4 f a b c = trustedSized . f (getSized a) (getSized b) (getSized c) . getSized+{-# INLINE overSized4 #-}++-- | Wrap and unwrap 'Sized' (unsafe, be sure 'f' is size-conservative)+overSized5 :: (a -> b -> c -> d -> e -> f) -> Sized s a -> Sized s b -> Sized s c -> Sized s d -> Sized s e -> Sized s f+overSized5 f a b c d = trustedSized . f (getSized a) (getSized b) (getSized c) (getSized d) . getSized+{-# INLINE overSized5 #-}++-- | Wrap and unwrap 'Sized' (unsafe, be sure 'f' is respects output size)+trustedChangeOverSized :: (a -> b) -> Sized s0 a -> Sized s1 b+trustedChangeOverSized f = trustedSized . f . getSized+{-# INLINE trustedChangeOverSized #-}++-- | Wrap and unwrap 'Sized' (unsafe, be sure 'f' is respects output size)+trustedChangeOverSized2 :: (a -> b -> c) -> Sized s0 a -> Sized s1 b -> Sized s2 c+trustedChangeOverSized2 f a = trustedSized . f (getSized a) . getSized+{-# INLINE trustedChangeOverSized2 #-}++-- | Wrap and unwrap 'Sized' (unsafe, be sure 'f' is respects output size)+trustedChangeOverSized3 :: (a -> b -> c -> d) -> Sized s0 a -> Sized s1 b -> Sized s2 c -> Sized s3 d+trustedChangeOverSized3 f a b = trustedSized . f (getSized a) (getSized b) . getSized+{-# INLINE trustedChangeOverSized3 #-}++-- | Wrap and unwrap 'Sized' (unsafe, be sure 'f' is respects output size)+trustedChangeOverSized4 :: (a -> b -> c -> d -> e) -> Sized s0 a -> Sized s1 b -> Sized s2 c -> Sized s3 d -> Sized s4 e+trustedChangeOverSized4 f a b c = trustedSized . f (getSized a) (getSized b) (getSized c) . getSized+{-# INLINE trustedChangeOverSized4 #-}++-- | Wrap and unwrap 'Sized' (unsafe, be sure 'f' is respects output size)+trustedChangeOverSized5 :: (a -> b -> c -> d -> e -> f) -> Sized s0 a -> Sized s1 b -> Sized s2 c -> Sized s3 d -> Sized s4 e -> Sized s5 f+trustedChangeOverSized5 f a b c d = trustedSized . f (getSized a) (getSized b) (getSized c) (getSized d) . getSized+{-# INLINE trustedChangeOverSized5 #-}++-- | 'fmap' over a 'Sized' container+fmapSized :: Functor f => (a -> b) -> Sized s (f a) -> Sized s (f b)+fmapSized f = overSized (fmap f)+{-# INLINE fmapSized #-}++-- | Apply an unsafe function over empty, which is safe over 'Sized'+withSized :: (a -> Maybe b) -> Sized s a -> b+withSized f = fromJust . f . getSized+{-# INLINE withSized #-}++-- | Trusted value+trustedSized :: a -> Sized s a+trustedSized = Sized+{-# INLINE trustedSized #-}++-- | Unknown value+unknownSized :: a -> Sized Unknown a+unknownSized = Sized+{-# INLINE unknownSized #-}++-- | Singleton constructible value+class SizedSingleton a where+ type SizedSingletonElement a :: Type+ sizedSingleton :: Proxy a -> SizedSingletonElement a -> a++-- | Build a 'Sized' value from a singleton value+singleton :: SizedSingleton a => Proxy a -> SizedSingletonElement a -> Sized (Exactly 1) a+singleton p = trustedSized . sizedSingleton p+{-# INLINE singleton #-}++-- | Build 'SizedSingleton' for 'Applicative' defined types+-- to be used with 'DerivingVia':+--+-- > deriving instance SizedSingleton [a] via (MkSizedSingletonApplicative [a])+newtype MkSizedSingletonApplicative a+ = MkSizedSingletonApplicative a++instance Applicative f => SizedSingleton (f a) where+ type SizedSingletonElement (f a) = a+ sizedSingleton _ = pure++-- * From container++-- | Used to attempt conversion from possibly any size to 'Sized'.+class SizedFromContainer a where+ calculateSize :: a -> Int+ isAtLeast :: Int -> a -> Bool+ isAtLeast n = (>= n) . calculateSize+ isAtMost :: Int -> a -> Bool+ isAtMost n = (<= n) . calculateSize+ isExactly :: Int -> a -> Bool+ isExactly n = (== n) . calculateSize+ isBetween :: Int -> Int -> a -> Bool+ isBetween n m = inRange (n, m) . calculateSize++-- | Convert a container from possibly any size to 'Sized'.+class Size s where+ sized :: SizedFromContainer a => a -> Maybe (Sized s a)++instance Size Unknown where+ sized = Just . trustedSized++instance KnownNat n => Size (Exactly n) where+ sized = mkSized $ isExactly $ fromInteger $ natVal $ Proxy @n++instance KnownNat n => Size (AtLeast n) where+ sized = mkSized $ isAtLeast $ fromInteger $ natVal $ Proxy @n++instance KnownNat n => Size (AtMost n) where+ sized = mkSized $ isAtMost $ fromInteger $ natVal $ Proxy @n++instance (KnownNat n, KnownNat m, n <= m) => Size (Between n m) where+ sized = mkSized $ isBetween (fromInteger $ natVal $ Proxy @n) (fromInteger $ natVal $ Proxy @m)++mkSized :: (a -> Bool) -> a -> Maybe (Sized s a)+mkSized p x =+ if p x+ then Just $ trustedSized x+ else Nothing++-- | Build 'MkSizedFromContainerFoldable' for 'Foldable' defined types+-- to be used with 'DerivingVia':+--+-- > deriving instance SizedFromContainer [a] via (MkSizedFromContainerFoldable [a])+newtype MkSizedFromContainerFoldable a+ = MkSizedFromContainerFoldable a++instance Foldable f => SizedFromContainer (f a) where+ calculateSize = length+ isExactly n = (== [n]) . drop n . index+ isAtLeast n = not . null . drop n . index+ isAtMost n = null . drop n . toList+ isBetween n m x =+ let indexed = index x+ in elem n indexed && notElem (succ m) indexed++index :: Foldable f => f a -> [Int]+index = (0 :) . zipWith const [1 ..] . toList++-- | Give a more precise sizing+precise :: (SizedFromContainer a, Size s) => Sized s' a -> Maybe (Sized s a)+precise = sized . getSized+{-# INLINE precise #-}++type family IsMoreGeneral general restrictive :: Constraint where+ IsMoreGeneral (AtLeast n) (AtLeast m) = (n <= m)+ IsMoreGeneral (AtMost n) (AtMost m) = (m <= n)+ IsMoreGeneral (AtLeast n) (Exactly m) = (n <= m)+ IsMoreGeneral (AtMost n) (Exactly m) = (m <= n)+ IsMoreGeneral (AtLeast n) (Between m o) = (n <= m)+ IsMoreGeneral (AtMost n) (Between m o) = (o <= n)+ IsMoreGeneral (Between n m) (Between o p) = (n <= o, p <= m)+ IsMoreGeneral (Between n m) (Exactly o) = (n <= o, o <= m)+ IsMoreGeneral Unknown a = ()++type IsNotEmpty s = IsMoreGeneral s (Exactly 1)++-- | Give a more general sizing+approximate :: IsMoreGeneral s s' => Sized s' a -> Sized s a+approximate = trustedSized . getSized+{-# INLINE approximate #-}++-- | Concatenative operation of 'Sized'+withSizedAppend :: (a -> b -> c) -> Sized s a -> Sized s' b -> Sized (s <+> s') c+withSizedAppend f x y = trustedSized $ f (getSized x) (getSized y)++type family (<+>) a b where+ (<+>) Unknown b = Unknown+ (<+>) a Unknown = Unknown+ (<+>) (AtMost n) (AtMost m) = AtMost (n + m)+ (<+>) (AtMost n) (Exactly m) = AtMost (n + m)+ (<+>) (Exactly n) (Exactly m) = Exactly (n + m)+ (<+>) (Exactly n) (AtMost m) = AtMost (n + m)+ (<+>) (Exactly n) (AtLeast m) = AtLeast (n + m)+ (<+>) (AtLeast n) (Exactly m) = AtLeast (n + m)+ (<+>) (AtLeast n) (AtLeast m) = AtLeast (n + m)+ (<+>) (AtLeast n) (AtMost m) = Between n (n + m)+ (<+>) (AtMost n) (AtLeast m) = Between m (n + m)+ (<+>) (AtLeast n) (Between m o) = Between (n + m) (n + o)+ (<+>) (AtMost n) (Between m o) = Between m (n + o)+ (<+>) (Between n m) (Exactly o) = Between (n + o) (m + o)+ (<+>) (Exactly o) (Between n m) = Between (n + o) (m + o)+ (<+>) (Between m o) (AtLeast n) = Between (n + m) (n + o)+ (<+>) (Between m o) (AtMost n) = Between m (n + o)+ (<+>) (Between n m) (Between o p) = Between (n + o) (m + p)++-- | Semigroup append+(<<>>) :: Semigroup a => Sized s a -> Sized s' a -> Sized (s <+> s') a+(<<>>) = withSizedAppend (<>)+{-# INLINE (<<>>) #-}++infixr 6 <<>>++type family RestrictAtMost a where+ RestrictAtMost Unknown = Unknown+ RestrictAtMost (AtMost n) = AtMost n+ RestrictAtMost (AtLeast n) = AtLeast 0+ RestrictAtMost (Between n m) = AtMost m+ RestrictAtMost (Exactly n) = AtMost n++withSizedRetract :: (a -> b) -> Sized s a -> Sized (RestrictAtMost s) b+withSizedRetract f = trustedSized . f . getSized++type family (<->) a b where+ (<->) Unknown b = Unknown+ (<->) a Unknown = Unknown+ (<->) (AtMost n) (AtMost m) = AtMost (n - m)+ (<->) (Exactly n) (AtMost m) = AtMost (n - m)+ (<->) (AtMost n) (Exactly m) = AtMost (n - m)+ (<->) (Exactly n) (Exactly m) = Exactly (n - m)+ (<->) (Exactly n) (AtLeast m) = AtLeast (n - m)+ (<->) (AtLeast n) (Exactly m) = AtLeast (n - m)+ (<->) (AtLeast n) (AtLeast m) = AtLeast (n - m)+ (<->) (AtLeast n) (AtMost m) = AtLeast (n - m)+ (<->) (AtMost n) (AtLeast m) = AtLeast 0+ (<->) (AtLeast n) (Between m o) = AtLeast (m - n)+ (<->) (AtMost n) (Between m o) = Between (m - n) o+ (<->) (Between n m) (Exactly o) = Between (n - o) (m - o)+ (<->) (Exactly o) (Between n m) = Between (o - n) (o - m)+ (<->) (Between m o) (AtLeast n) = AtLeast 0+ (<->) (Between m o) (AtMost n) = Between m (o - n)+ (<->) (Between n m) (Between o p) = Between (n - o) (m - p)++withSizedSubtract :: (a -> b -> c) -> Sized s a -> Sized s' b -> Sized (s <-> s') c+withSizedSubtract f a b = trustedSized $ f (getSized a) (getSized b)++type family (<*>) a b where+ (<*>) Unknown b = Unknown+ (<*>) a Unknown = Unknown+ (<*>) (AtMost n) (AtMost m) = AtMost (n TypeLits.* m)+ (<*>) (Exactly n) (AtMost m) = AtMost (n TypeLits.* m)+ (<*>) (AtMost n) (Exactly m) = AtMost (n TypeLits.* m)+ (<*>) (Exactly n) (Exactly m) = Exactly (n TypeLits.* m)+ (<*>) (AtLeast n) (Exactly m) = AtLeast (n TypeLits.* m)+ (<*>) (Exactly n) (AtLeast m) = AtLeast (n TypeLits.* m)+ (<*>) (AtLeast n) (AtLeast m) = AtLeast (n TypeLits.* m)+ (<*>) (AtLeast n) (AtMost m) = AtLeast 0+ (<*>) (AtMost n) (AtLeast m) = AtLeast 0+ (<*>) (AtLeast n) (Between m o) = AtLeast (m TypeLits.* n)+ (<*>) (AtMost n) (Between m o) = AtLeast 0+ (<*>) (Between n m) (Exactly o) = Between (n TypeLits.* o) (m TypeLits.* o)+ (<*>) (Exactly o) (Between n m) = Between (n TypeLits.* o) (m TypeLits.* o)+ (<*>) (Between m o) (AtLeast n) = AtLeast (m TypeLits.* n)+ (<*>) (Between m o) (AtMost n) = AtLeast 0+ (<*>) (Between n m) (Between o p) = Between (n TypeLits.* o) (m TypeLits.* p)++withSizedProduct :: (a -> b -> c) -> Sized s a -> Sized s' b -> Sized (s <*> s') c+withSizedProduct f a b = trustedSized $ f (getSized a) (getSized b)++type family Includes (sized :: Type) (size :: Nat) :: Constraint where+ Includes (AtLeast n) m = (n <= m)+ Includes (AtMost n) m = (m <= n)+ Includes (Between n m) o = (n <= o, o <= m)+ Includes Unknown a = ()
+ test/Data/SizedSpec.hs view
@@ -0,0 +1,99 @@+{-# LANGUAGE NoOverloadedLists #-}+{-# LANGUAGE NoOverloadedStrings #-}++module Data.SizedSpec+ ( main,+ spec,+ )+where++import Data.Proxy+import Data.Sized+import Test.Hspec++main :: IO ()+main = hspec spec++spec :: Spec+spec = do+ it "Singleton creation should be equivalent to a single element list" $+ singleton (Proxy @[Int]) 42 `shouldBe` trustedSized [42]+ describe "sized creation" $ do+ describe "Exactly" $ do+ it "(Exactly 3) on three items list should be equivalent to the wrapped list" $+ sized @(Exactly 3) @[Int] [1, 2, 3] `shouldBe` Just (trustedSized [1, 2, 3])+ it "(Exactly 0) on empty list should be equivalent to the wrapped list" $+ sized @(Exactly 0) @[Int] [] `shouldBe` Just (trustedSized [])+ it "(Exactly 3) on empty list should be Nothing" $+ sized @(Exactly 3) @[Int] [] `shouldBe` Nothing+ describe "AtLeast" $ do+ it "(AtLeast 3) on three items list should be equivalent to the wrapped list" $+ sized @(AtLeast 3) @[Int] [1, 2, 3] `shouldBe` Just (trustedSized [1, 2, 3])+ it "(AtLeast 0) on empty list should be equivalent to the wrapped list" $+ sized @(AtLeast 0) @[Int] [] `shouldBe` Just (trustedSized [])+ it "(AtLeast 3) on empty list should be Nothing" $+ sized @(AtLeast 3) @[Int] [] `shouldBe` Nothing+ describe "AtMost" $ do+ it "(AtMost 3) on three items list should be equivalent to the wrapped list" $+ sized @(AtMost 3) @[Int] [1, 2, 3] `shouldBe` Just (trustedSized [1, 2, 3])+ it "(AtMost 0) on empty list should be equivalent to the wrapped list" $+ sized @(AtMost 0) @[Int] [] `shouldBe` Just (trustedSized [])+ it "(AtMost 3) on a 4-items list should be Nothing" $+ sized @(AtMost 3) @[Int] [1, 2, 3, 4] `shouldBe` Nothing+ describe "Between" $ do+ it "(Between 3 3) on three items list should be equivalent to the wrapped list" $+ sized @(Between 3 3) @[Int] [1, 2, 3] `shouldBe` Just (trustedSized [1, 2, 3])+ it "(Between 0 0) on empty list should be equivalent to the wrapped list" $+ sized @(Between 0 0) @[Int] [] `shouldBe` Just (trustedSized [])+ it "(Between 3 3) on a 4-items list should be Nothing" $+ sized @(Between 3 3) @[Int] [1, 2, 3, 4] `shouldBe` Nothing+ it "(Between 2 4) on three items list should be equivalent to the wrapped list" $+ sized @(Between 2 4) @[Int] [1, 2, 3] `shouldBe` Just (trustedSized [1, 2, 3])+ it "(Between 0 4) on empty list should be equivalent to the wrapped list" $+ sized @(Between 0 4) @[Int] [] `shouldBe` Just (trustedSized [])+ it "(Between 1 3) on a 4-items list should be Nothing" $+ sized @(Between 1 3) @[Int] [1, 2, 3, 4] `shouldBe` Nothing+ it "(Between 5 7) on a 4-items list should be Nothing" $+ sized @(Between 5 7) @[Int] [1, 2, 3, 4] `shouldBe` Nothing+ describe "approximate" $ do+ describe "Exactly" $ do+ it "(Exactly 3) approximates to (Between 3 3)" $+ approximate (trustedSized @[Int] @(Exactly 3) [1, 2, 3]) `shouldBe` trustedSized @[Int] @(Between 3 3) [1, 2, 3]+ it "(Exactly 3) approximates to (Between 0 3)" $+ approximate (trustedSized @[Int] @(Exactly 3) [1, 2, 3]) `shouldBe` trustedSized @[Int] @(Between 0 3) [1, 2, 3]+ it "(Exactly 3) approximates to (Between 3 5)" $+ approximate (trustedSized @[Int] @(Exactly 3) [1, 2, 3]) `shouldBe` trustedSized @[Int] @(Between 3 5) [1, 2, 3]+ it "(Exactly 3) approximates to (AtLeast 3)" $+ approximate (trustedSized @[Int] @(Exactly 3) [1, 2, 3]) `shouldBe` trustedSized @[Int] @(AtLeast 3) [1, 2, 3]+ it "(Exactly 3) approximates to (AtMost 3)" $+ approximate (trustedSized @[Int] @(Exactly 3) [1, 2, 3]) `shouldBe` trustedSized @[Int] @(AtMost 3) [1, 2, 3]+ it "(Exactly 3) approximates to (AtLeast 1)" $+ approximate (trustedSized @[Int] @(Exactly 3) [1, 2, 3]) `shouldBe` trustedSized @[Int] @(AtLeast 1) [1, 2, 3]+ it "(Exactly 3) approximates to (AtMost 5)" $+ approximate (trustedSized @[Int] @(Exactly 3) [1, 2, 3]) `shouldBe` trustedSized @[Int] @(AtMost 5) [1, 2, 3]+ describe "AtLeast" $ do+ it "(AtLeast 3) approximates to (AtLeast 2)" $+ approximate (trustedSized @[Int] @(AtLeast 3) [1, 2, 3]) `shouldBe` trustedSized @[Int] @(AtLeast 2) [1, 2, 3]+ describe "AtMost" $ do+ it "(AtMost 3) approximates to (AtMost 4)" $+ approximate (trustedSized @[Int] @(AtMost 3) [1, 2, 3]) `shouldBe` trustedSized @[Int] @(AtMost 4) [1, 2, 3]+ describe "Between" $ do+ it "(Between 3 3) approximates to (Between 3 3)" $+ approximate (trustedSized @[Int] @(Between 3 3) [1, 2, 3]) `shouldBe` trustedSized @[Int] @(Between 3 3) [1, 2, 3]+ it "(Between 3 3) approximates to (Between 0 3)" $+ approximate (trustedSized @[Int] @(Between 3 3) [1, 2, 3]) `shouldBe` trustedSized @[Int] @(Between 0 3) [1, 2, 3]+ it "(Between 3 3) approximates to (Between 3 5)" $+ approximate (trustedSized @[Int] @(Between 3 3) [1, 2, 3]) `shouldBe` trustedSized @[Int] @(Between 3 5) [1, 2, 3]+ it "(Between 3 3) approximates to (AtLeast 3)" $+ approximate (trustedSized @[Int] @(Between 3 3) [1, 2, 3]) `shouldBe` trustedSized @[Int] @(AtLeast 3) [1, 2, 3]+ it "(Between 3 3) approximates to (AtMost 3)" $+ approximate (trustedSized @[Int] @(Between 3 3) [1, 2, 3]) `shouldBe` trustedSized @[Int] @(AtMost 3) [1, 2, 3]+ it "(Between 3 3) approximates to (AtLeast 1)" $+ approximate (trustedSized @[Int] @(Between 3 3) [1, 2, 3]) `shouldBe` trustedSized @[Int] @(AtLeast 1) [1, 2, 3]+ it "(Between 3 3) approximates to (AtMost 5)" $+ approximate (trustedSized @[Int] @(Between 3 3) [1, 2, 3]) `shouldBe` trustedSized @[Int] @(AtMost 5) [1, 2, 3]++-- it "prepend should use semigroup" $+-- singleton (Proxy @[Int]) 1 <| [2] `shouldBe` trustedSized [1, 2]+-- it "append should use semigroup" $+-- [1] |> singleton (Proxy @[Int]) 2 `shouldBe` trustedSized [1, 2]
+ test/Spec.hs view
@@ -0,0 +1,1 @@+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}