これは、より高いレベルの構造の代わりに、変更可能なボックス化されていないベクトルを使用した実装です。conduitまた、遅延 I/O を回避するためにファイルの読み取りにも使用します。
import Control.Monad.IO.Class
import qualified Data.ByteString as S
import Data.Conduit
import Data.Conduit.Binary as CB
import qualified Data.Conduit.List as CL
import qualified Data.Vector.Unboxed.Mutable as VM
import Data.Word (Word8)
type Freq = VM.IOVector Int
newFreq :: MonadIO m => m Freq
newFreq = liftIO $ VM.replicate 256 0
printFreq :: MonadIO m => Freq -> m ()
printFreq freq =
liftIO $ mapM_ go [0..255]
where
go i = do
x <- VM.read freq i
putStrLn $ show i ++ ": " ++ show x
addFreqWord8 :: MonadIO m => Freq -> Word8 -> m ()
addFreqWord8 f w = liftIO $ do
let index = fromIntegral w
oldCount <- VM.read f index
VM.write f index (oldCount + 1)
addFreqBS :: MonadIO m => Freq -> S.ByteString -> m ()
addFreqBS f bs =
loop (S.length bs - 1)
where
loop (-1) = return ()
loop i = do
addFreqWord8 f (S.index bs i)
loop (i - 1)
-- | The main entry point.
main :: IO ()
main = do
freq <- newFreq
runResourceT
$ sourceFile "random"
$$ CL.mapM_ (addFreqBS freq)
printFreq freq
これを 500MB のランダム データで実行し、@josejuan の UArray ベースの回答と比較しました。
- コンジットベース/可変ベクトル: 1.006s
- Uアレイ: 17.962秒
josejuan のハイレベルなアプローチの優雅さの多くを維持しながら、可変ベクトル実装の速度を維持することは可能だと思いますが、そのようなものを実装する機会はまだありません。また、一部の汎用ヘルパー関数 (Data.ByteString.mapM や Data.Conduit.Binary.mapM など) を使用すると、パフォーマンスに影響を与えずに実装を大幅に簡素化できることに注意してください。
FP Haskell Center でもこの実装を試すことができます。
編集:不足している機能の1つを追加conduitし、コードを少しクリーンアップしました。次のようになります。
import Control.Monad.Trans.Class (lift)
import Data.ByteString (ByteString)
import Data.Conduit (Consumer, ($$))
import qualified Data.Conduit.Binary as CB
import qualified Data.Vector.Unboxed as V
import qualified Data.Vector.Unboxed.Mutable as VM
import System.IO (stdin)
freqSink :: Consumer ByteString IO (V.Vector Int)
freqSink = do
freq <- lift $ VM.replicate 256 0
CB.mapM_ $ \w -> do
let index = fromIntegral w
oldCount <- VM.read freq index
VM.write freq index (oldCount + 1)
lift $ V.freeze freq
main :: IO ()
main = (CB.sourceHandle stdin $$ freqSink) >>= print
機能上の唯一の違いは、周波数がどのように出力されるかです。