loop 0.2.0 → 0.3.0
raw patch · 5 files changed
+61/−7 lines, 5 filesdep +foldlsetup-changedPVP ok
version bump matches the API change (PVP)
Dependencies added: foldl
API changes (from Hackage documentation)
+ Control.Loop: forLoopState :: Monad m => a -> (a -> Bool) -> (a -> a) -> b -> (b -> a -> m b) -> m b
+ Control.Loop: numLoopState :: (Num a, Eq a, Monad m) => a -> a -> b -> (b -> a -> m b) -> m b
- Control.Loop: numLoop :: (Num a, Eq a, Monad m) => a -> a -> (a -> m ()) -> m ()
+ Control.Loop: numLoop :: (Num a, Ord a, Monad m) => a -> a -> (a -> m ()) -> m ()
Files
- Setup.hs +0/−2
- bench/Bench.hs +3/−0
- loop.cabal +3/−2
- src/Control/Loop.hs +29/−2
- test/Main.hs +26/−1
− Setup.hs
@@ -1,2 +0,0 @@-import Distribution.Simple-main = defaultMain
bench/Bench.hs view
@@ -2,6 +2,7 @@ module Main (main) where +import qualified Control.Foldl as Foldl import Control.Monad import Criterion.Main import qualified Data.Vector as V@@ -41,6 +42,7 @@ , bench "uvectorEnumFromToInt" $ nfIO $ uvectorEnumFromToInt 0 (1000000 :: Int) (\_ -> return ()) -- Allocates the vector -> linear space and slow -- , bench "uvectorEnumFromNInt" $ nfIO $ uvectorEnumFromNInt 0 (1000000 :: Int) (\_ -> return ())+ , bench "FoldL.FoldM" $ nfIO $ Foldl.foldM (Foldl.FoldM (\_m _x -> return ()) (return ()) return) [1..1000000::Int] ] , bgroup "w32" [ bench "loop" $ nfIO $ loop 0 (1000000 :: Word32) (\_ -> return ())@@ -57,6 +59,7 @@ , bench "vectorEnumFromToW32" $ nfIO $ vectorEnumFromToW32 0 (1000000 :: Word32) (\_ -> return ()) , bench "uvectorFromListW32" $ nfIO $ uvectorFromListW32 0 (1000000 :: Word32) (\_ -> return ()) , bench "uvectorEnumFromToW32" $ nfIO $ uvectorEnumFromToW32 0 (1000000 :: Word32) (\_ -> return ())+ , bench "FoldL.FoldM" $ nfIO $ Foldl.foldM (Foldl.FoldM (\_m _x -> return ()) (return ()) return) [1..1000000::Word32] ] -- `succ` is almost twice as slow as (+1) because it does an overflow check.
loop.cabal view
@@ -1,5 +1,5 @@ name: loop-version: 0.2.0+version: 0.3.0 license: MIT copyright: 2014 Niklas Hambüchen <mail@nh2.me> author: Niklas Hambüchen <mail@nh2.me>@@ -17,7 +17,7 @@ `forM_ [1..n]` idiom, which in many cases GHC cannot fuse to efficient code. .- See https://ghc.haskell.org/trac/ghc/ticket/8763.+ See <https://ghc.haskell.org/trac/ghc/ticket/8763>. source-repository head type: git@@ -64,6 +64,7 @@ , criterion >= 0.6.0.0 , random >= 1.0.1.1 , vector >= 0.10.9.1+ , foldl >= 1.0.0 ghc-options: -Wall -O2
src/Control/Loop.hs view
@@ -26,8 +26,10 @@ -- @forLoop 1 (<= n) (+1)@. module Control.Loop ( forLoop+ , forLoopState , forLoopFold , numLoop+ , numLoopState , numLoopFold ) where @@ -43,6 +45,17 @@ {-# INLINE forLoop #-} +-- | @forLoopState start cond inc initialState f@: A C-style for loop with+-- starting value, loop condition, incrementor and a state that is threaded+-- through the computation.+forLoopState :: (Monad m) => a -> (a -> Bool) -> (a -> a) -> b -> (b -> a -> m b) -> m b+forLoopState start cond inc initialState f = go start initialState+ where+ go !x !state | cond x = f state x >>= go (inc x)+ | otherwise = return state++{-# INLINE forLoopState #-}+ -- | @forLoopFold start cond inc acc0 f@: A pure fold using a for loop -- instead of a list for performance. --@@ -62,15 +75,29 @@ -- | @numLoop start end f@: Loops over a contiguous numerical range, including -- @end@. --+-- Does nothing when not @start <= end@.+-- -- It uses @(+ 1)@ so for most integer types it has no bounds (overflow) check.-numLoop :: (Num a, Eq a, Monad m) => a -> a -> (a -> m ()) -> m ()-numLoop start end f = go start+numLoop :: (Num a, Ord a, Monad m) => a -> a -> (a -> m ()) -> m ()+numLoop start end f = if start <= end then go start else return () where go !x | x == end = f x | otherwise = f x >> go (x+1) {-# INLINE numLoop #-} +-- | @numLoopState start end f initialState@: Loops over a contiguous numerical+-- range, including @end@ threading a state through the computation.+--+-- It uses @(+ 1)@ so for most integer types it has no bounds (overflow) check.+numLoopState :: (Num a, Eq a, Monad m) => a -> a -> b -> (b -> a -> m b) -> m b+numLoopState start end initState f = go start initState+ where+ go !x !state | x == end = f state x+ | otherwise = f state x >>= go (x+1)+++{-# INLINE numLoopState #-} -- | @numLoopFold start end acc0 f@: A pure fold over a contiguous numerical -- range, including @end@.
test/Main.hs view
@@ -5,7 +5,7 @@ import Data.Word import Test.Hspec -import Control.Loop (forLoop, numLoop, numLoopFold)+import Control.Loop main :: IO ()@@ -53,6 +53,18 @@ res `shouldBe` (maxBound :: Word32) + describe "forLoopState" $ do++ it "monadic and threaded state" $ do+ let res = flip execState 0 $ do+ _ <- forLoopState (0 :: Int) (<= 10) (+1) (1 :: Int) $ \st i -> do+ x <- get+ put $! x + st + i+ return (st * 2)+ return ()++ res `shouldBe` sum (map (\a -> a + 2 ^ a) [0 .. 10])+ describe "numLoop" $ do it "is inclusive" $ do@@ -62,6 +74,19 @@ put $! x + i res `shouldBe` 55+++ describe "numLoopState" $ do++ it "monadic and threaded state" $ do+ let res = flip execState 0 $ do+ _ <- numLoopState (0 :: Int) 10 (1 :: Int) $ \st i -> do+ x <- get+ put $! x + st + i+ return (st * 2)+ return ()++ res `shouldBe` sum (map (\a -> a + 2 ^ a) [0 .. 10]) describe "numLoopFold" $ do