writeSTRef twice for each iteration
fib3 :: Int -> Integer
fib3 n = runST $ do
a <- newSTRef 1
b <- newSTRef 1
replicateM_ (n-1) $ do
!a' <- readSTRef a
!b' <- readSTRef b
writeSTRef a b'
writeSTRef b $! a'+b'
readSTRef b
writeSTRef once for each iteration
fib4 :: Int -> Integer
fib4 n = runST $ do
a <- newSTRef 1
b <- newSTRef 1
replicateM_ (n-1) $ do
!a' <- readSTRef a
!b' <- readSTRef b
if a' > b'
then writeSTRef b $! a'+b'
else writeSTRef a $! a'+b'
a'' <- readSTRef a
b'' <- readSTRef b
if a'' > b''
then return a''
else return b''
Benchmark, given n = 20000:
benchmarking 20000/fib3
mean: 5.073608 ms, lb 5.071842 ms, ub 5.075466 ms, ci 0.950
std dev: 9.284321 us, lb 8.119454 us, ub 10.78107 us, ci 0.950
benchmarking 20000/fib4
mean: 5.384010 ms, lb 5.381876 ms, ub 5.386099 ms, ci 0.950
std dev: 10.85245 us, lb 9.510215 us, ub 12.65554 us, ci 0.950
fib3 is a bit faster than fib4.