Haskell でいくつかの単純な文字カウント ルーチンを作成し、統計を新しいデータ型に格納しています。
data Stat = Stat {
stChars :: !Int,
stVowels :: !Int,
stPairEL :: !Int,
stWords :: !Int
}
これを、それぞれ約 50K ~ 100K の数百または数千のプレーンテキスト ファイルで実行しています。
tabulateFile :: FilePath -> IO Stat
tabulateFile path = do
putStrLn path
contents <- L.readFile path
return $! tabulateText ' ' contents defaultStat
左折を使用する代わりに、プリミティブ再帰を使用しているため、前の文字を保持できます。
tabulateText :: Char -> L.ByteString -> Stat -> Stat
tabulateText lastChr bs stat =
case U.uncons bs of
Nothing -> stat
Just (chr, newBs) ->
tabulateText lchr newBs (countChar lastChr lchr stat)
where lchr = toLower chr
{-# INLINE countChar #-}
countChar :: Char -> Char -> Stat -> Stat
countChar !lastChr !chr !(Stat stChars stVowels stPairEL stWords) =
Stat
(stChars + 1)
(stVowels + (countIf $ isVowel chr))
(stPairEL + (countIf (lastChr == 'e' && chr == 'l')))
(stWords + (countIf ((not $ isLetter lastChr) && isLetter chr)))
isVowel :: Char -> Bool
isVowel c = Set.member c vowels
vowels = Set.fromAscList ['a', 'e', 'i', 'o', 'u', ...] -- rest of vowels elided
現時点では、実行cat * | wc
中の 2 倍以上遅いですが、ファイル I/O が必要な CPU 時間をかなりのマージンで上回っているはずだと直感的にわかります。ホットキャッシュで約 20MB/s のプロセスを使用するだけcat * | wc
ですが、私の Haskell プログラム ( でコンパイル-O
) を使用すると、いくつかの基本的な最適化の後でも、10MB/s 未満で実行されます。プロファイリングによると、ほとんどの時間は と で費やされtabulateText
ていcountChar
ます。
ここで最適化できることを見逃しているものはありますか?
編集: http://hpaste.org/74638に貼り付けられた完全なファイル