parent
1d610d5096
commit
43a6269dcd
6 changed files with 341 additions and 0 deletions
@ -0,0 +1,75 @@ |
||||
# Basic Libraries |
||||
|
||||
## 28.6 Exercise: Benchmark Practice |
||||
|
||||
see [src/benchSet.hs](./src/benchSet.hs) |
||||
|
||||
```shell |
||||
benchmarking member check map |
||||
time 28.57 ns (28.10 ns .. 29.11 ns) |
||||
0.998 R² (0.996 R² .. 0.999 R²) |
||||
mean 28.43 ns (28.09 ns .. 28.97 ns) |
||||
std dev 1.357 ns (899.3 ps .. 1.950 ns) |
||||
variance introduced by outliers: 70% (severely inflated) |
||||
|
||||
benchmarking member check set |
||||
time 27.93 ns (27.55 ns .. 28.34 ns) |
||||
0.998 R² (0.997 R² .. 0.999 R²) |
||||
mean 27.92 ns (27.58 ns .. 28.38 ns) |
||||
std dev 1.320 ns (1.010 ns .. 1.940 ns) |
||||
variance introduced by outliers: 70% (severely inflated) |
||||
|
||||
benchmarking insert check set |
||||
time 127.9 ns (127.4 ns .. 128.4 ns) |
||||
1.000 R² (1.000 R² .. 1.000 R²) |
||||
mean 127.1 ns (126.7 ns .. 127.6 ns) |
||||
std dev 1.515 ns (1.162 ns .. 2.043 ns) |
||||
variance introduced by outliers: 12% (moderately inflated) |
||||
|
||||
benchmarking insert check set |
||||
time 112.8 ns (112.4 ns .. 113.3 ns) |
||||
1.000 R² (1.000 R² .. 1.000 R²) |
||||
mean 112.6 ns (112.0 ns .. 113.4 ns) |
||||
std dev 2.414 ns (1.889 ns .. 3.151 ns) |
||||
variance introduced by outliers: 30% (moderately inflated) |
||||
|
||||
benchmarking union check set |
||||
time 655.5 μs (652.0 μs .. 658.8 μs) |
||||
1.000 R² (0.999 R² .. 1.000 R²) |
||||
mean 638.7 μs (634.2 μs .. 642.7 μs) |
||||
std dev 15.07 μs (12.96 μs .. 18.02 μs) |
||||
variance introduced by outliers: 14% (moderately inflated) |
||||
|
||||
benchmarking union check set |
||||
time 428.9 μs (423.5 μs .. 433.8 μs) |
||||
0.999 R² (0.999 R² .. 0.999 R²) |
||||
mean 422.6 μs (419.7 μs .. 425.9 μs) |
||||
std dev 10.16 μs (8.544 μs .. 12.44 μs) |
||||
variance introduced by outliers: 15% (moderately inflated) |
||||
``` |
||||
|
||||
## 28.9 Excercises: Vector |
||||
|
||||
see [src/benchVector.hs](./src/benchVector.hs) |
||||
|
||||
Using unboxed vector has better time performance. I tried measuring space, |
||||
but the difference is almost negligable. |
||||
|
||||
## 28.10 Chaper Exercises |
||||
|
||||
### Difference List |
||||
|
||||
see [src/DiffList.hs](./src/DiffList.hs) |
||||
|
||||
It is not actually faster, but it has the same performance as Data.DList and |
||||
the same implementation, so I guess this is to be expected? |
||||
|
||||
### A simple queue |
||||
|
||||
see [src/SimpleQueue.hs](./src/SimpleQueue.hs) |
||||
|
||||
Comparing Sequence and Queue seems a bit strange as they serve different |
||||
purposes. I could implement a function to add something to the back of the |
||||
queue (similar to |>) but that kinda defeats the purpose of queue... I compared |
||||
them based on what a queue should be capable of doing and it seem the queue |
||||
is better than the sequence in these cases. |
@ -0,0 +1,61 @@ |
||||
module Main where |
||||
|
||||
import Criterion.Main |
||||
|
||||
-- import qualified Data.DList as DL |
||||
|
||||
newtype DList a = DL { unDL :: [a] -> [a] } |
||||
|
||||
-- 1 |
||||
empty :: DList a |
||||
empty = DL id |
||||
{-# INLINE empty #-} |
||||
|
||||
-- 2 |
||||
singleton :: a -> DList a |
||||
singleton = DL . (:) |
||||
{-# INLINE singleton #-} |
||||
|
||||
-- 3 |
||||
toList :: DList a -> [a] |
||||
toList dl = unDL dl [] |
||||
{-# INLINE toList #-} |
||||
|
||||
-- 4 |
||||
infixr `cons` |
||||
cons :: a -> DList a -> DList a |
||||
cons x xs = DL ((x:) . unDL xs) |
||||
{-# INLINE cons #-} |
||||
|
||||
-- 5 |
||||
infixl `snoc` |
||||
snoc :: DList a -> a -> DList a |
||||
snoc xs x = DL $ ((unDL xs) . (x:)) |
||||
{-# INLINE snoc #-} |
||||
|
||||
-- 6 |
||||
append :: DList a -> DList a -> DList a |
||||
append d d' = DL $ (unDL d . unDL d') |
||||
{-# INLINE append #-} |
||||
|
||||
schlemiel :: Int -> [Int] |
||||
schlemiel i = go i [] |
||||
where go 0 xs = xs |
||||
go n xs = go (n - 1) ([n] ++ xs) |
||||
|
||||
constructDList :: Int -> [Int] |
||||
constructDList i = toList $ go i empty |
||||
where go 0 xs = xs |
||||
go n xs = go (n - 1) (singleton n `append` xs) |
||||
|
||||
-- constructDList' :: Int -> [Int] |
||||
-- constructDList' i = DL.toList $ go i DL.empty |
||||
-- where go 0 xs = xs |
||||
-- go n xs = go (n - 1) (DL.singleton n `DL.append` xs) |
||||
|
||||
main :: IO () |
||||
main = defaultMain |
||||
[ bench "concat list" $ whnf schlemiel 123456 |
||||
, bench "concat dlist" $ whnf constructDList 123456 |
||||
-- , bench "concat dlist'" $ whnf constructDList' 123456 |
||||
] |
@ -0,0 +1,106 @@ |
||||
module Main where |
||||
|
||||
import Criterion.Main |
||||
import qualified Data.Sequence as S |
||||
|
||||
data Queue a = Queue { enqueue :: [a] |
||||
, dequeue :: [a] |
||||
} deriving (Show, Eq) |
||||
|
||||
empty :: Queue a |
||||
empty = Queue [] [] |
||||
|
||||
push :: a -> Queue a -> Queue a |
||||
push a q = q { enqueue = a : enqueue q} |
||||
|
||||
pop :: Queue a -> Maybe (a, Queue a) |
||||
pop (Queue [] []) = Nothing |
||||
pop (Queue xs []) = pop $ Queue [] (reverse xs) |
||||
pop (Queue xs (y:ys)) = Just (y, Queue xs ys) |
||||
|
||||
alternateQ :: [Int] -> Bool |
||||
alternateQ [] = True |
||||
alternateQ (x:xs) = go x empty && alternateQ xs |
||||
where go y q = f (pop $ push y q) y |
||||
f Nothing _ = False |
||||
f (Just (a, _)) b = a == b |
||||
|
||||
pushL :: a -> [a] -> [a] |
||||
pushL = (:) |
||||
|
||||
popL :: [a] -> Maybe (a, [a]) |
||||
popL [] = Nothing |
||||
popL xs = let xs' = reverse xs |
||||
in Just (head $ xs', reverse $ tail xs') |
||||
|
||||
alternateL :: [Int] -> Bool |
||||
alternateL [] = True |
||||
alternateL (x:xs) = go x [] && alternateL xs |
||||
where go y q = f (popL $ pushL y q) y |
||||
f Nothing _ = False |
||||
f (Just (a, _)) b = a == b |
||||
|
||||
pushThenPop :: [Int] -> [Int] |
||||
pushThenPop xs = (go' $ go xs empty) |
||||
where go [] q = q |
||||
go (y:ys) q = go ys (push y q) |
||||
go' q = let r = pop q |
||||
in case r of |
||||
Nothing -> [] |
||||
(Just (a, q')) -> a : go' q' |
||||
|
||||
pushThenPopL :: [Int] -> [Int] |
||||
pushThenPopL xs = (go' $ go xs []) |
||||
where go [] q = q |
||||
go (y:ys) q = go ys (pushL y q) |
||||
go' q = let r = popL q |
||||
in case r of |
||||
Nothing -> [] |
||||
(Just (a, q')) -> a : go' q' |
||||
|
||||
-- |
||||
fromList :: [a] -> Queue a |
||||
fromList = flip Queue [] |
||||
|
||||
fromList' :: [a] -> Queue a |
||||
fromList' = Queue [] . reverse |
||||
|
||||
(><) :: Queue a -> Queue a -> Queue a |
||||
(><) (Queue e d) (Queue e' d') = Queue [] q'' |
||||
where q'' = d ++ reverse e ++ d' ++ reverse e' |
||||
|
||||
testConcat :: [Int] -> Queue Int |
||||
testConcat xs = fromList xs >< fromList xs |
||||
|
||||
testConcat' :: [Int] -> S.Seq Int |
||||
testConcat' xs = S.fromList xs S.>< S.fromList xs |
||||
|
||||
pushA :: [Int] -> Queue Int |
||||
pushA xs = go xs empty |
||||
where go [] q = q |
||||
go (x:xs) q = go xs $ push x q |
||||
|
||||
pushA' :: [Int] -> S.Seq Int |
||||
pushA' xs = go xs S.empty |
||||
where go [] s = s |
||||
go (x:xs) s = go xs $ x S.<| s |
||||
|
||||
main :: IO () |
||||
main = defaultMain |
||||
-- List will be faster because it has no overehead for Queue construction |
||||
-- and queue still needs to reverse for every element just as list. |
||||
[ bench "queue" $ nf alternateQ [1..1000] |
||||
, bench "list" $ nf alternateL [1..1000] |
||||
-- List will be slower than queue, because it needs to reverse for every |
||||
-- element, while queue only reverse on empty dequeue. |
||||
, bench "queue push pop" $ nf pushThenPop [1..1000] |
||||
, bench "list push pop" $ nf pushThenPopL [1..1000] |
||||
-- Queue is quite efficient at what it is good at: |
||||
, bench "queue fromList" $ whnf fromList ([1..1000] :: [Int]) |
||||
, bench "queue fromList'" $ whnf fromList' ([1..1000] :: [Int]) |
||||
, bench "sequence fromList" $ whnf S.fromList ([1..1000] :: [Int]) |
||||
, bench "queue concat" $ whnf testConcat ([1..100] :: [Int]) |
||||
, bench "sequence concat" $ whnf testConcat' ([1..100] :: [Int]) |
||||
, bench "insert queue" $ whnf pushA [1..1000] |
||||
, bench "insert sequence" $ whnf pushA' [1..1000] |
||||
] |
@ -0,0 +1,23 @@ |
||||
module Main where |
||||
|
||||
import Control.Monad |
||||
import qualified Data.Text as T |
||||
import qualified Data.Text.IO as TIO |
||||
import qualified System.IO as SIO |
||||
import qualified Data.Text.Lazy as TL |
||||
import qualified Data.Text.Lazy.IO as TLIO |
||||
|
||||
dictWords :: IO String |
||||
dictWords = SIO.readFile "/usr/share/dict/words" |
||||
|
||||
dictWordsT :: IO T.Text |
||||
dictWordsT = TIO.readFile "/usr/share/dict/words" |
||||
|
||||
dictWordsTL :: IO TL.Text |
||||
dictWordsTL = TLIO.readFile "/usr/share/dict/words" |
||||
|
||||
main :: IO () |
||||
main = do |
||||
replicateM_ 1000 (dictWords >>= print) |
||||
replicateM_ 1000 (dictWordsT >>= TIO.putStrLn) |
||||
replicateM_ 1000 (dictWordsTL >>= TLIO.putStrLn) |
@ -0,0 +1,52 @@ |
||||
module Main where |
||||
|
||||
import Criterion.Main |
||||
import qualified Data.Map as M |
||||
import qualified Data.Set as S |
||||
|
||||
bumpIt :: (Num a, Num b) => (a, b) -> (a, b) |
||||
bumpIt (i, v) = (i + 1, v + 1) |
||||
|
||||
m :: M.Map Int Int |
||||
m = M.fromList $ take 10000 stream |
||||
where stream = iterate bumpIt (0, 0) |
||||
|
||||
s :: S.Set Int |
||||
s = S.fromList $ take 10000 stream |
||||
where stream = iterate (+1) 0 |
||||
|
||||
membersMap :: Int -> Bool |
||||
membersMap i = M.member i m |
||||
|
||||
membersSet :: Int -> Bool |
||||
membersSet i = S.member i s |
||||
|
||||
insertMap :: (Int, Int) -> M.Map Int Int |
||||
insertMap (k, v) = M.insert k v m |
||||
|
||||
insertSet :: Int -> S.Set Int |
||||
insertSet k = S.insert k s |
||||
|
||||
m1 :: M.Map Int Int |
||||
m1 = M.fromList $ take 5000 stream |
||||
where stream = iterate (bumpIt . bumpIt) (0, 0) |
||||
m2 :: M.Map Int Int |
||||
m2 = M.fromList $ take 5000 stream |
||||
where stream = iterate (bumpIt . bumpIt) (1, 1) |
||||
|
||||
s1 :: S.Set Int |
||||
s1 = S.fromList $ take 5000 stream |
||||
where stream = iterate (+2) 0 |
||||
s2 :: S.Set Int |
||||
s2 = S.fromList $ take 5000 stream |
||||
where stream = iterate (+2) 1 |
||||
|
||||
main :: IO () |
||||
main = defaultMain |
||||
[ bench "member check map" $ whnf (membersMap) 9999 |
||||
, bench "member check set" $ whnf (membersSet) 9999 |
||||
, bench "insert check set" $ whnf (insertMap) (10001, 10001) |
||||
, bench "insert check set" $ whnf (insertSet) 100001 |
||||
, bench "union check set" $ whnf (M.union m1) m2 |
||||
, bench "union check set" $ whnf (S.union s1) s2 |
||||
] |
@ -0,0 +1,24 @@ |
||||
module Main where |
||||
|
||||
import Criterion.Main |
||||
import qualified Data.Vector as BV |
||||
import qualified Data.Vector.Unboxed as UV |
||||
|
||||
import Control.Monad |
||||
|
||||
total :: Int |
||||
total = 10^6 |
||||
|
||||
boxed :: BV.Vector Bool |
||||
boxed = BV.fromList $ replicate total True |
||||
|
||||
unboxed :: UV.Vector Bool |
||||
unboxed = UV.fromList $ replicate total True |
||||
|
||||
main :: IO () |
||||
main = |
||||
defaultMain |
||||
[ |
||||
bench "any boxed" $ whnf (BV.and) boxed, |
||||
bench "any unboxed" $ whnf (UV.and) unboxed |
||||
] |
Loading…
Reference in new issue