packages feed

hw-streams (empty) → 0.0.0.1

raw patch · 18 files changed

+602/−0 lines, 18 filesdep +QuickCheckdep +basedep +bytestringsetup-changed

Dependencies added: QuickCheck, base, bytestring, criterion, directory, exceptions, ghc-prim, hedgehog, hspec, hw-bits, hw-hspec-hedgehog, hw-prim, hw-streams, mmap, primitive, semigroups, transformers, vector

Files

+ LICENSE view
@@ -0,0 +1,30 @@+Copyright John Ky (c) 2016++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 Author name here 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 OR CONTRIBUTORS 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.
+ README.md view
@@ -0,0 +1,10 @@+# hw-streams++[![CircleCI](https://circleci.com/gh/haskell-works/hw-streams/tree/master.svg?style=svg)](https://circleci.com/gh/haskell-works/hw-streams/tree/master)+[![Travis](https://travis-ci.org/haskell-works/hw-streams.svg?branch=master)](https://travis-ci.org/haskell-works/hw-streams)++Pure streaming library.++This is a reproduction of the work in [Exploiting Vector Instructions with Generalized Stream Fusion][1]++[1]: https://www.microsoft.com/en-us/research/wp-content/uploads/2016/07/haskell-beats-C.pdf
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ bench/Baseline/Data/Streams/Vector/Storable.hs view
@@ -0,0 +1,9 @@+module Baseline.Data.Streams.Vector.Storable where++import qualified Data.Vector.Storable                      as DVS+import qualified HaskellWorks.Data.Streams.Vector.Storable as DVS++-- | Version of map that does not do fusion+map :: (DVS.Storable a, DVS.Storable b) => (a -> b) -> DVS.Vector a -> DVS.Vector b+map f = DVS.unstream . fmap f . DVS.stream+{-# INLINE map #-}
+ bench/Main.hs view
@@ -0,0 +1,63 @@+{-# LANGUAGE BangPatterns        #-}+{-# LANGUAGE ScopedTypeVariables #-}++module Main where++import Control.Monad  (join)+import Criterion.Main+import Data.Word++import qualified Baseline.Data.Streams.Vector.Storable     as USDVS+import qualified Data.Vector.Storable                      as DVS+import qualified HaskellWorks.Data.Streams.Stream          as S+import qualified HaskellWorks.Data.Streams.Vector.Storable as SDVS+import qualified Reference.Data.Streams.Vector.Storable    as DVS++mkReplicateVector :: IO (DVS.Vector Word64)+mkReplicateVector = do+  let !v = DVS.replicate 100000 (0 :: Word64)+  return v++mkEnumVector :: IO (DVS.Vector Word64)+mkEnumVector = do+  let !v = SDVS.enumFromStepN 0 1 100000+  return v++mkEnumVector2 :: IO (DVS.Vector Word64, DVS.Vector Word64)+mkEnumVector2 = do+  let !v = SDVS.enumFromStepN 0 1 100000+  let !w = SDVS.enumFromStepN 0 1 100000+  return (v, w)++sumall :: DVS.Vector Word64 -> Word64+sumall = S.foldl (+) 123 . SDVS.stream . SDVS.map (+1) . SDVS.map (+1) . SDVS.map (+1)++runMap :: DVS.Vector Word64 -> DVS.Vector Word64+runMap = SDVS.map (+123) . SDVS.map (+123) . SDVS.map (+123)++runMapUnfused :: DVS.Vector Word64 -> DVS.Vector Word64+runMapUnfused = USDVS.map (+123) . USDVS.map (+123) . USDVS.map (+123)++benchThings :: [Benchmark]+benchThings = join $+  [ [ env mkReplicateVector $ \v -> bgroup "mkReplicateVector"+      [ bench "DVS.map"         (whnf runMap              v)+      , bench "DVS.mapUnfused"  (whnf runMapUnfused       v)+      ]+    ]+  , [ env mkEnumVector $ \v -> bgroup "mkEnumVector"+      [ bench "DVS.map"         (whnf runMap              v)+      , bench "DVS.mapUnfused"  (whnf runMapUnfused       v)+      , bench "DVS.sumall"      (whnf sumall              v)+      , bench "DVS.foldl"       (whnf (SDVS.foldl (+) 0)  v)+      ]+    ]+  , [ env mkEnumVector2 $ \ ~(v, w) -> bgroup "mkEnumVector2"+      [ bench "SDVS.dotp"        (whnf (SDVS.dotp v)       w)+      , bench "DVS.dotp"         (whnf (DVS.dotp v)       w)+      ]+    ]+  ]++main :: IO ()+main = defaultMain benchThings
+ bench/Reference/Data/Streams/Vector/Storable.hs view
@@ -0,0 +1,8 @@+module Reference.Data.Streams.Vector.Storable where++import Data.Vector.Storable (Storable)++import qualified Data.Vector.Storable as DVS++dotp :: (Storable a, Num a) => DVS.Vector a -> DVS.Vector a -> a+dotp v w = DVS.sum (DVS.zipWith (*) v w)
+ hw-streams.cabal view
@@ -0,0 +1,123 @@+-- This file has been generated from package.yaml by hpack version 0.18.1.+--+-- see: https://github.com/sol/hpack++name:           hw-streams+version:        0.0.0.1+synopsis:       Primitive functions and data types+description:    Primitive functions and data types.+category:       Data+stability:      Experimental+homepage:       http://github.com/haskell-works/hw-streams#readme+bug-reports:    https://github.com/haskell-works/hw-streams/issues+author:         John Ky+maintainer:     newhoggy@gmail.com+copyright:      2016-2018 John Ky+license:        BSD3+license-file:   LICENSE+tested-with:    GHC == 8.4.2, GHC == 8.2.2, GHC == 8.0.2, GHC == 7.10.3+build-type:     Simple+cabal-version:  >= 1.10++extra-source-files:+    README.md++source-repository head+  type: git+  location: https://github.com/haskell-works/hw-streams++flag bounds-checking-enabled+  description: Enable bmi2 instruction set+  manual: False+  default: False++library+  hs-source-dirs:+      src+  other-extensions: AllowAmbiguousTypes+  ghc-options: -Wall -O2 -msse4.2+  build-depends:+      base            >= 4.8        && < 5+    , bytestring      >= 0.9        && < 0.11+    , ghc-prim        >= 0.5.1.1    && < 0.6+    , hw-bits         >= 0.7.0.3    && < 0.8+    , hw-prim         >= 0.6.2.17   && < 0.7+    , mmap            >= 0.5        && < 0.6+    , primitive       >= 0.6.3.0    && < 0.7+    , vector          >= 0.12       && < 0.13+    , semigroups      >= 0.8.4      && < 0.19+    , transformers    >= 0.4        && < 0.6+  if flag(bounds-checking-enabled)+    cpp-options: -DBOUNDS_CHECKING_ENABLED+  exposed-modules:+      HaskellWorks.Data.Streams.Internal+      HaskellWorks.Data.Streams.Internal.Bundle+      HaskellWorks.Data.Streams.Internal.Chunk+      HaskellWorks.Data.Streams.Size+      HaskellWorks.Data.Streams.Stream+      HaskellWorks.Data.Streams.Stream.Ops+      HaskellWorks.Data.Streams.Vector+      HaskellWorks.Data.Streams.Vector.Storable+  other-modules:+      Paths_hw_streams+  default-language: Haskell2010++test-suite hw-streams-test+  type: exitcode-stdio-1.0+  main-is: Spec.hs+  hs-source-dirs:+      test+  other-extensions: AllowAmbiguousTypes+  ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-N+  build-depends:+      base            >= 4.8        && < 5+    , bytestring      >= 0.9        && < 0.11+    , ghc-prim        >= 0.5.1.1    && < 0.6+    , hw-bits         >= 0.7.0.3    && < 0.8+    , hw-prim         >= 0.6.2.17   && < 0.7+    , mmap            >= 0.5        && < 0.6+    , primitive       >= 0.6.3.0    && < 0.7+    , vector          >= 0.12       && < 0.13+    , semigroups      >= 0.8.4      && < 0.19+    , transformers    >= 0.4        && < 0.6+    , QuickCheck          >= 2.10       && < 2.12+    , directory           >= 1.2        && < 1.4+    , exceptions          >= 0.8        && < 0.11+    , hedgehog            >= 0.5        && < 0.7+    , hspec               >= 2.4        && < 2.6+    , hw-hspec-hedgehog   >= 0.1        && < 0.2+    , hw-streams+  if flag(bounds-checking-enabled)+    cpp-options: -DBOUNDS_CHECKING_ENABLED+  other-modules:+      HaskellWorks.Data.Stream.Vector.StorableSpec+      Test.Gen+  default-language: Haskell2010++benchmark bench+  type: exitcode-stdio-1.0+  main-is: Main.hs+  hs-source-dirs:+      bench+  other-extensions: AllowAmbiguousTypes+  ghc-options: -Wall -O2 -msse4.2+  build-depends:+      base            >= 4.8        && < 5+    , bytestring      >= 0.9        && < 0.11+    , ghc-prim        >= 0.5.1.1    && < 0.6+    , hw-bits         >= 0.7.0.3    && < 0.8+    , hw-prim         >= 0.6.2.17   && < 0.7+    , mmap            >= 0.5        && < 0.6+    , primitive       >= 0.6.3.0    && < 0.7+    , vector          >= 0.12       && < 0.13+    , semigroups      >= 0.8.4      && < 0.19+    , transformers    >= 0.4        && < 0.6+    , criterion     >= 1.2      && < 1.6+    , hw-streams+    , mmap          >= 0.5      && < 0.6+  if flag(bounds-checking-enabled)+    cpp-options: -DBOUNDS_CHECKING_ENABLED+  other-modules:+      Baseline.Data.Streams.Vector.Storable+      Reference.Data.Streams.Vector.Storable+  default-language: Haskell2010
+ src/HaskellWorks/Data/Streams/Internal.hs view
@@ -0,0 +1,5 @@+module HaskellWorks.Data.Streams.Internal where++inplace :: a -> a+inplace = id+{-# INLINE [1] inplace #-}
+ src/HaskellWorks/Data/Streams/Internal/Bundle.hs view
@@ -0,0 +1,13 @@+module HaskellWorks.Data.Streams.Internal.Bundle where++import HaskellWorks.Data.Streams.Internal.Chunk (Chunk)++import qualified HaskellWorks.Data.Streams.Stream as S++type Size = Int++data Bundle a = Bundle+  { bundleSize   :: Size+  , bundleElems  :: S.Stream a+  , bundleChunks :: S.Stream (Chunk a)+  }
+ src/HaskellWorks/Data/Streams/Internal/Chunk.hs view
@@ -0,0 +1,12 @@+{-# LANGUAGE RankNTypes #-}++module HaskellWorks.Data.Streams.Internal.Chunk where++import Control.Monad.Primitive++import qualified Data.Vector.Storable as DVS++data Chunk a = Chunk+  { chunkSize  :: Int+  , chunkWrite :: forall m. PrimMonad m => DVS.MVector (PrimState m) a -> m ()+  }
+ src/HaskellWorks/Data/Streams/Size.hs view
@@ -0,0 +1,7 @@+module HaskellWorks.Data.Streams.Size+  ( Size(..)+  , smaller+  , larger+  ) where++import Data.Vector.Fusion.Bundle.Size
+ src/HaskellWorks/Data/Streams/Stream.hs view
@@ -0,0 +1,103 @@+{-# LANGUAGE CPP   #-}+{-# LANGUAGE GADTs #-}++module HaskellWorks.Data.Streams.Stream where++import Data.Bool+import HaskellWorks.Data.Streams.Size++import Prelude hiding (drop, zipWith)++data Stream a where+  Stream :: ()+    => (s -> Step s a)+    -> s+    -> Size+    -> Stream a++instance Functor Stream where+  fmap f (Stream step s i) = Stream (fmap f <$> step) s i+  {-# INLINE fmap #-}++data Step s a+  = Yield a s+  | Skip s+  | Done++instance Functor (Step s) where+  fmap f (Yield a s) = Yield (f a) s+  fmap _ (Skip s)    = Skip s+  fmap _ Done        = Done+  {-# INLINE fmap #-}++zipWith :: (a -> b -> c) -> Stream a -> Stream b -> Stream c+zipWith f (Stream stepa sa na) (Stream stepb sb nb) = Stream step (sa, sb, Nothing) (smaller na nb)+  where step (ta, tb, Nothing) = case stepa ta of+          Yield xa ta0 -> Skip (ta0, tb, Just xa)+          Skip ta0     -> Skip (ta0, tb, Nothing)+          Done         -> Done+        step (ta, tb, Just xa) = case stepb tb of+          Yield y tb0 -> Yield (f xa y) (ta, tb0, Nothing)+          Skip tb0    -> Skip (ta, tb0, Just xa)+          Done        -> Done+        {-# INLINE [0] step #-}+{-# INLINE [1] zipWith #-}++zipWithState :: (a -> b -> s -> (c, s)) -> s -> Stream a -> Stream b -> Stream c+zipWithState f state (Stream stepa sa na) (Stream stepb sb nb) = Stream step (sa, sb, Nothing, state) (smaller na nb)+  where step (ta, tb, Nothing, oldState) = case stepa ta of+          Yield xa ta0 -> Skip (ta0, tb, Just xa, oldState)+          Skip ta0     -> Skip (ta0, tb, Nothing, oldState)+          Done         -> Done+        step (ta, tb, Just xa, oldState) = case stepb tb of+          Yield y tb0 -> let (newValue, newState) = f xa y state in Yield newValue (ta, tb0, Nothing, newState)+          Skip tb0    -> Skip (ta, tb0, Just xa, oldState)+          Done        -> Done+        {-# INLINE [0] step #-}+{-# INLINE [1] zipWithState #-}++enumFromStepN :: Num a => a -> a -> Int -> Stream a+enumFromStepN x y n = x `seq` y `seq` n `seq` Stream step (x, n) (Exact n)+  where step (w, m) | m > 0     = Yield w (w + y, m - 1)+                    | otherwise = Done+        {-# INLINE [0] step #-}+{-# INLINE [1] enumFromStepN #-}++foldl :: (a -> b -> a) -> a -> Stream b -> a+foldl f z (Stream step s _) = loop z s+  where loop za sa = za `seq` case step sa of+          Yield x sb -> loop (f za x) sb+          Skip sb    -> loop za sb+          Done       -> za+{-# INLINE [1] foldl #-}++drop :: Int -> Stream a -> Stream a+drop n s@(Stream step state size) = if n > 0+  then case step state of+    Yield _ newState -> drop (n - 1)  $ Stream step newState (size - 1)+    Skip newState    -> drop  n       $ Stream step newState size+    Done             -> s+  else s++{-# RULES+  "zipWith xs xs [Vector.Stream]" forall f xs. zipWith f xs xs = fmap (\x -> f x x) xs   #-}++append :: Stream a -> Stream a -> Stream a+append (Stream stepa ta na) (Stream stepb tb nb) = Stream step (Left ta) (na + nb)+  where step (Left sa) = case stepa sa of+          Yield x sa' -> Yield x (Left  sa')+          Skip    sa' -> Skip    (Left  sa')+          Done        -> Skip    (Right tb)+        step (Right sb) = case stepb sb of+          Yield x sb' -> Yield x (Right sb')+          Skip    sb' -> Skip    (Right sb')+          Done        -> Done+        {-# INLINE step #-}+{-# INLINE append #-}++singleton :: a -> Stream a+singleton a = Stream (bool Done (Yield a False)) True 1++repeat :: Int -> a -> Stream a+repeat n a = Stream step n 1+  where step i = if i > 0 then Yield a (i - 1) else Done
+ src/HaskellWorks/Data/Streams/Stream/Ops.hs view
@@ -0,0 +1,41 @@+{-# LANGUAGE MagicHash #-}++module HaskellWorks.Data.Streams.Stream.Ops where++import Data.Word+import GHC.Int+import GHC.Prim+import GHC.Word                         hiding (ltWord)+import HaskellWorks.Data.Bits.BitWise   ((.&.), (.<.), (.>.), (.^.), (.|.))+import HaskellWorks.Data.Positioning+import HaskellWorks.Data.Streams.Stream++import qualified HaskellWorks.Data.Bits.BitWise   as BW+import qualified HaskellWorks.Data.Streams.Stream as HW++ltWord :: Word64 -> Word64 -> Word64+ltWord (W64# a#) (W64# b#) = fromIntegral (I64# (ltWord# a# b#))+{-# INLINE ltWord #-}++comp :: Stream Word64 -> Stream Word64+comp = fmap BW.comp++bitwiseAnd :: Stream Word64 -> Stream Word64 -> Stream Word64+bitwiseAnd = HW.zipWith (.&.)++bitwiseOr :: Stream Word64 -> Stream Word64 -> Stream Word64+bitwiseOr = HW.zipWith (.|.)++bitwiseXor :: Stream Word64 -> Stream Word64 -> Stream Word64+bitwiseXor = HW.zipWith (.^.)++bitwiseShiftDown :: Count -> Stream Word64 -> Stream Word64+bitwiseShiftDown n as = HW.zipWith splice bs (HW.drop 1 bs `append` HW.singleton 0)+  where bs = HW.drop i as `append` HW.repeat i 0+        o = n `mod` 64+        i = fromIntegral (n `div` 64)+        splice :: Word64 -> Word64 -> Word64+        splice a b = (a .>. o) .|. (b .<. (64 - o))++add :: Stream Word64 -> Stream Word64 -> Stream Word64+add = HW.zipWithState (\a b c -> let d = a + b in (c + d, d `ltWord` a)) 0
+ src/HaskellWorks/Data/Streams/Vector.hs view
@@ -0,0 +1,46 @@+{-# LANGUAGE ScopedTypeVariables #-}++module HaskellWorks.Data.Streams.Vector where++import Control.Monad+import Control.Monad.ST+import HaskellWorks.Data.Streams.Internal+import HaskellWorks.Data.Streams.Size+import HaskellWorks.Data.Streams.Stream++import qualified Data.Vector                      as DV+import qualified Data.Vector.Mutable              as DVM+import qualified HaskellWorks.Data.Streams.Stream as HW++unstream :: forall a. HW.Stream a -> DV.Vector a+unstream (HW.Stream step initialState size) = runST $ do+  v <- case size of+    Exact n -> DVM.unsafeNew n+    Max   n -> DVM.unsafeNew n+    Unknown -> DVM.unsafeNew (32 * 1024)+  loop step v 0 initialState+  where loop :: (s -> Step s a) -> DVM.MVector t a -> Int -> s -> ST t (DV.Vector a)+        loop g v i s = case g s of+            Yield a s' -> do+              when (i >= DVM.length v) $ void $ DVM.unsafeGrow v (i * 2)+              DVM.unsafeWrite v i a+              loop g v (i + 1) s'+            Skip s0 -> loop g v i s0+            Done -> DV.freeze v+{-# INLINE [1] unstream #-}++stream :: forall a. DV.Vector a -> Stream a+stream v = Stream step 0 (Exact len)+  where len = DV.length v+        step i = if i >= len+          then Done+          else Yield (DV.unsafeIndex v i) (i + 1)+{-# INLINE [1] stream #-}++map :: (a -> b) -> DV.Vector a -> DV.Vector b+map f = unstream . inplace (fmap f) . stream+{-# INLINE map #-}++{-# RULES+  "stream/unstream" forall f. stream (unstream f) = f+  #-}
+ src/HaskellWorks/Data/Streams/Vector/Storable.hs view
@@ -0,0 +1,84 @@+{-# LANGUAGE ScopedTypeVariables #-}++module HaskellWorks.Data.Streams.Vector.Storable+  ( stream+  , unstream++  , map+  , zipWith++  , enumFromStepN+  , foldl++  , dotp+  , sum+  ) where++import Control.Monad+import Control.Monad.ST+import Data.Vector.Storable               (Storable)+import HaskellWorks.Data.Streams.Internal (inplace)+import HaskellWorks.Data.Streams.Size+import HaskellWorks.Data.Streams.Stream   (Step (..), Stream (..))+import Prelude                            hiding (foldl, map, sum, zipWith)++import qualified Data.Vector.Storable             as DVS+import qualified Data.Vector.Storable.Mutable     as DVSM+import qualified HaskellWorks.Data.Streams.Stream as S++unstream :: forall a. Storable a => S.Stream a -> DVS.Vector a+unstream (S.Stream step initialState size) = runST $ do+  v <- case size of+    Exact n -> DVSM.unsafeNew n+    Max   n -> DVSM.unsafeNew n+    Unknown -> DVSM.unsafeNew (32 * 1024)+  loop step v 0 initialState+  where loop :: (s -> Step s a) -> DVSM.MVector t a -> Int -> s -> ST t (DVS.Vector a)+        loop g v i s = case g s of+            Yield a s' -> do+              when (i >= DVSM.length v) $ void $ DVSM.unsafeGrow v (i * 2)+              DVSM.unsafeWrite v i a+              loop g v (i + 1) s'+            Skip s0 -> loop g v i s0+            Done -> DVS.freeze v+{-# INLINE [1] unstream #-}++stream :: forall a. Storable a => DVS.Vector a -> Stream a+stream v = Stream step 0 (Exact len)+  where len = DVS.length v+        step i = if i >= len+          then Done+          else Yield (DVS.unsafeIndex v i) (i + 1)+{-# INLINE [1] stream #-}++map :: (Storable a, Storable b)+  => (a -> b)+  -> DVS.Vector a+  -> DVS.Vector b+map f = unstream . inplace (fmap f) . stream+{-# INLINE map #-}++zipWith :: (Storable a, Storable b, Storable c)+  => (a -> b -> c)+  -> DVS.Vector a+  -> DVS.Vector b+  -> DVS.Vector c+zipWith f v w = unstream (S.zipWith f (stream v) (stream w))++enumFromStepN :: (Num a, Storable a) => a -> a -> Int -> DVS.Vector a+enumFromStepN x y = unstream . inplace (S.enumFromStepN x y)+{-# INLINE [1] enumFromStepN #-}++foldl :: Storable b => (a -> b -> a) -> a -> DVS.Vector b -> a+foldl f z = inplace (S.foldl f z) . stream+{-# INLINE [1] foldl #-}++sum :: (Storable a, Num a) => DVS.Vector a -> a+sum = foldl (+) 0++dotp :: (Storable a, Num a) => DVS.Vector a -> DVS.Vector a -> a+dotp v w = sum (zipWith (*) v w)++{-# RULES+  "stream/unstream" forall f. stream (unstream f) = f+  #-}
+ test/HaskellWorks/Data/Stream/Vector/StorableSpec.hs view
@@ -0,0 +1,33 @@+{-# LANGUAGE OverloadedStrings   #-}+{-# LANGUAGE ScopedTypeVariables #-}++module HaskellWorks.Data.Stream.Vector.StorableSpec+  ( spec+  ) where++import HaskellWorks.Hspec.Hedgehog+import Hedgehog+import Test.Hspec++import qualified Data.Vector.Storable                      as DVS+import qualified HaskellWorks.Data.Streams.Vector.Storable as SDVS+import qualified Hedgehog.Gen                              as G+import qualified Hedgehog.Range                            as R+import qualified Test.Gen                                  as G++{-# ANN module ("HLint: Ignore Redundant do" :: String) #-}++spec :: Spec+spec = describe "HaskellWorks.Data.Stream.Vector.StorableSpec" $ do+  it "map" $ requireProperty $ do+    v <- forAll $ G.vector (R.linear 0 100) (G.word64 (R.constantBounded))++    DVS.map (+ 1) v === SDVS.map (+ 1) v+  it "foldl" $ requireProperty $ do+    v <- forAll $ G.vector (R.linear 0 100) (G.word64 (R.constantBounded))++    DVS.foldl (+) 0 v === SDVS.foldl (+) 0 v+  it "sum" $ requireProperty $ do+    v <- forAll $ G.vector (R.linear 0 100) (G.word64 (R.constantBounded))++    DVS.sum v === SDVS.sum v
+ test/Spec.hs view
@@ -0,0 +1,1 @@+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
+ test/Test/Gen.hs view
@@ -0,0 +1,12 @@+module Test.Gen where++import Data.Vector.Storable        (Storable)+import HaskellWorks.Hspec.Hedgehog+import Hedgehog+import Test.Hspec++import qualified Data.Vector.Storable as DVS+import qualified Hedgehog.Gen         as G++vector :: (MonadGen m, Storable a) => Range Int -> m a -> m (DVS.Vector a)+vector r g = DVS.fromList <$> G.list r g