Haskell中的内存有效字符串

Grz*_*ała 23 string haskell

通常推荐的Haskell字符串类型似乎是ByteString或Text.我经常使用大量短(英文单词大小)字符串,并且通常需要将它们存储在诸如Data.Map的查找表中.在许多情况下,我发现在这种情况下,字符串表可以占用比ByteStrings表更少的内存.Word8的Unboxed Data.Vectors也比ByteStrings更紧凑.

当需要在Haskell中存储和比较大量小字符串时,最佳做法是什么?

下面我试图将一个特定问题的案例压缩成一个小例子:

import qualified Data.ByteString.Lazy.Char8 as S
import qualified Data.ByteString as Strict
import qualified Data.Map as Map
import qualified Data.Vector.Unboxed as U
import qualified Data.Serialize as Serialize
import Control.Monad.State

main =   putStr 
  . unlines . map show . flip evalState (0,Map.empty) 
  . mapM toInt 
  . S.words
  =<<
  S.getContents


toInt x = do  
  let x' =   
          U.fromList . Strict.unpack .  -- Comment this line to increase memory usage
           Serialize.encode $ x  
  (i,t) <- get
  case Map.lookup x' t of
    Just j -> return j
    Nothing -> do 
      let i' = i + (1::Int)
      put (i', Map.insert x' i t)
      return i
Run Code Online (Sandbox Code Playgroud)

当我在包含大约400.000字的英文文本的文件上运行时,带有严格字节串键的版本使用大约50MB内存,带有Word8向量的版本使用6MB.

Dan*_*ton 5

在没有其他答案的情况下,我会在这里走出困境.

当需要在Haskell中存储和比较大量小字符串时,最佳做法是什么?

如果小字符串是人类可读的(例如英文单词),那么使用Text.如果它们只能由计算机读取,请使用ByteString.使用严格或惰性变体的决定取决于您如何构建和使用这些小字符串.

您不应该使用自己的未装箱VectorWord8.如果您遇到特定情况,其中常规String速度超过Text或者ByteString,则将详细信息放在StackOverflow上,我们将尝试找出原因.如果你进行详细的分析,并且可以证明一个未装箱VectorWord8一贯工作明显优于Text或者ByteString,那么就开始在邮件列表,irc,reddit等上进行对话; 标准库不是一成不变的,总是欢迎改进.

但是我觉得很有可能你只是在做一些奇怪的事情,正如hammar和shang所说的那样.

PS针对您的特定用例,而不是存储大量小字符串,您应该考虑更适合您需求的数据结构,例如,如danr所暗示的Trie.

  • 排序_short_字符串是一个常规`String`比`ByteString`表现更好的地方(我不知道'Text`,但如果`String`也为这个任务打败了我也不会感到惊讶).为什么这是显而易见的:`ByteString`使用计数排序. (4认同)