Skip to content

Instantly share code, notes, and snippets.

@minoki
Created February 22, 2018 12:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save minoki/9610b1c9113cf3787e221fcce7265f5b to your computer and use it in GitHub Desktop.
Save minoki/9610b1c9113cf3787e221fcce7265f5b to your computer and use it in GitHub Desktop.
関数内ローカル変数に IORef を使うな
{-# LANGUAGE MagicHash #-}
module Main where
import Data.IORef
import Control.Monad (forM_)
import System.Environment (getArgs)
import Control.Monad.State.Class
import qualified Control.Monad.State.Strict as StateStrict
import qualified Control.Monad.State.Lazy as StateLazy
import Control.Monad.Writer.Strict as WriterStrict
import GHC.Prim
import GHC.Types
{-# NOINLINE someCalculationWithRec #-}
someCalculationWithRec :: IO Int
someCalculationWithRec = return (loop 0 0)
where loop i acc | i > 10000 * 10000 = acc
| otherwise = loop (i+1) (acc + (i `rem` 3))
{-# NOINLINE someCalculationWithIORef #-}
someCalculationWithIORef :: IO Int
someCalculationWithIORef = do
sumRef <- newIORef (0 :: Int)
forM_ [0..10000 * 10000] $ \i -> do
modifyIORef' sumRef (+ (i `rem` 3))
readIORef sumRef
{-# NOINLINE someCalculationWithIORefLazy #-}
someCalculationWithIORefLazy :: IO Int
someCalculationWithIORefLazy = do
sumRef <- newIORef (0 :: Int)
forM_ [0..10000 * 10000] $ \i -> do
modifyIORef sumRef (+ (i `rem` 3))
readIORef sumRef
{-# NOINLINE someCalculationWithIORefRW #-}
someCalculationWithIORefRW :: IO Int
someCalculationWithIORefRW = do
sumRef <- newIORef (0 :: Int)
forM_ [0..10000 * 10000] $ \i -> do
s <- readIORef sumRef
writeIORef sumRef $! s + (i `rem` 3)
readIORef sumRef
{-# NOINLINE someCalculationWithState #-}
someCalculationWithState :: IO Int
someCalculationWithState = flip StateStrict.evalStateT 0 $ do
forM_ [0..10000 * 10000] $ \i -> do
modify' (+ (i `rem` 3))
get
{-# NOINLINE someCalculationWithStateLazy #-}
someCalculationWithStateLazy :: IO Int
someCalculationWithStateLazy = flip StateLazy.evalStateT 0 $ do
forM_ [0..10000 * 10000] $ \i -> do
modify' (+ (i `rem` 3))
get
{-# NOINLINE someCalculationWithWriter #-}
someCalculationWithWriter :: IO Int
someCalculationWithWriter = return $ getSum $ WriterStrict.execWriter $ do
forM_ [0..10000 * 10000] $ \i -> do
tell (Sum (i `rem` 3))
{-# NOINLINE someCalculationWithUnboxed #-}
someCalculationWithUnboxed :: IO Int
someCalculationWithUnboxed = return (I# (loop 0# 0#))
where loop i# acc# = case i# ># 100000000# of
1# -> acc#
_ -> loop (i# +# 1#) (acc# +# (i# `remInt#` 3#))
main :: IO ()
main = do
args <- getArgs
case args of
"Rec":_ -> someCalculationWithRec >>= print
"IORef":_ -> someCalculationWithIORef >>= print
"IORefLazy":_ -> someCalculationWithIORefLazy >>= print
"IORefRW":_ -> someCalculationWithIORefRW >>= print
"State":_ -> someCalculationWithState >>= print
"StateLazy":_ -> someCalculationWithStateLazy >>= print
"Writer":_ -> someCalculationWithWriter >>= print
"Unboxed":_ -> someCalculationWithUnboxed >>= print
_ -> putStrLn "argument: one of Rec, IORef, IORefLazy, IORefRW, State, StateLazy, Writer, Unboxed"
name: ioref-test
version: 0.1.0.0
license: BSD3
author: "ARATA Mizuki"
copyright: "2018 ARATA Mizuki"
dependencies:
- base >= 4.7 && < 5
- mtl
- ghc-prim
executables:
ioref-test-exe:
main: Main.hs
ghc-options:
- -threaded
- -ddump-simpl
- -ddump-asm
- -ddump-to-file
- -Wall
#include <stdio.h>
#include <memory>
int someCalculation()
{
int sum = 0;
for (int i = 0; i <= 10000 * 10000; ++i) {
sum += i % 3;
}
return sum;
}
int someCalculationWithPtr()
{
std::unique_ptr<int> sumRef{new int()};
for (int i = 0; i <= 10000 * 10000; ++i) {
*sumRef += i % 3;
}
return *sumRef;
}
int main(int argc, char *argv[])
{
if (argc > 1 && strcmp(argv[1], "ptr") == 0) {
printf("%d\n", someCalculationWithPtr());
} else {
printf("%d\n", someCalculation());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment