2009-02-23 81 views
23

我現在在教自己的Haskell,我想知道在Haskell中使用字符串時最佳做法是什麼。Haskell中有效的字符串實現

Haskell中的默認字符串實現是Char的列表。根據Real World Haskell,由於每個字符都是分開分配的(我假設這意味着一個字符串基本上是Haskell中的一個鏈表,但我不確定),所以這對於文件輸入輸出而言是低效的。

但是,如果缺省的字符串實現對於文件I/O來說是低效的,在內存中使用字符串的效率是否也是低效的?爲什麼或者爲什麼不? C使用一個char數組來表示一個String,並且我認爲這將是在大多數語言中做事的默認方式。

正如我所看到的,String的列表實現將佔用更多的內存,因爲每個字符都需要開銷,並且還需要更多時間來迭代,因爲需要指針取消引用來獲取下一個字符。但我很喜歡和Haskell一起玩,所以我想相信默認實現是有效的。

+0

對於小字符串以及想要對其執行的常見操作,默認實現是最方便使用的。對於想要基本上視爲字節塊的大型字符串,效率不高;使用Data.ByteString或Data.ByteString.Lazy – ShreevatsaR 2009-02-23 03:02:27

回答

30

在Haskell中正常使用字符串的最佳實踐基本上是:使用Data.ByteString/Data.ByteString.Lazy。

http://hackage.haskell.org/packages/archive/bytestring/latest/doc/html/


至於默認字符串執行的效率在Haskell去,事實並非如此。每個Char代表一個Unicode代碼點,這意味着它需要至少每個Char 21位。

由於String只是[Char],那就是Char一個鏈表,這意味着String■找的局部性差,並再次表示String s爲內存相當大,至少它是N * (21bits + Mbits)其中N是字符串的長度和M是指針的大小(32,64,你有什麼),而不像Haskell使用其他語言可能使用不同結構的其他地方(我在這裏特別考慮控制流),String編譯器對於循環等進行優化的可能性要小得多。

雖然Char對應於一個代碼點,但Haskell 98報告沒有指定執行文件IO時使用的編碼的任何內容,甚至不是默認的更改方式。在實踐中,GHC提供了一個擴展來做例如二進制IO,但無論如何你都要在這個位置進行預定。

即使有像預先放在字符串前面那樣的操作,在實際中String將不可能擊敗ByteString

+1

+1正是我要回答的包。 ByteString將字符串作爲偏移量存儲到字節數組中。 Data.ByteString.Char8允許你直接在ByteStrings中使用Chars,假定只有最低8位是重要的(即ASCII)。 ByteString還提供了自己的高效IO功能。 – 2009-02-23 01:00:25

8

答案比「使用懶惰的字節串」複雜一點。

  • 字節字符串只存儲每個值8位,而字符串保存真正的Unicode字符。因此,如果你想使用Unicode,那麼你必須始終轉換爲UTF-8或UTF-16,這比使用字符串更昂貴。不要認爲你的程序只需要ASCII就是錯誤的。除非它只是一次性代碼,那麼有一天有人需要輸入一個歐元符號(U + 20AC)或重音字符,並且你的快速字符串實現將會被無法挽回地破壞。
  • 字節字符串有些事情,比如預先考慮字符串的開頭,更昂貴。

也就是說,如果你需要性能,你可以純粹用字節表示你的數據,那麼這樣做。

33

除了字符串/字節串,現在有Text庫結合了兩個世界中最好的一個 - 它在內部使用基於ByteString的Unicode,它可以工作,因此你可以得到快速,正確的字符串。

+0

不錯; +1,謝謝Porges。 – 2009-03-09 15:52:48

6

給出最基本的答案,使用字節串,是正確的。這就是說,我之前的三個答案都有不準確之處。

關於UTF-8:這是否會是一個問題,或不完全依賴於什麼樣的處理你與你的琴絃做的。如果你只是簡單地將它們視爲單個數據塊(包括諸如級聯之類的操作,儘管不是分割)或者執行某些有限的基於字節的操作(例如,以字節爲單位查找字符串的長度,而不是以字符),你不會有任何問題。如果您使用的是I18N,還有其他問題,只需使用String而不是ByteString即可開始解決您遇到的幾個問題。

前面加上一個字節一個字節串的前很可能比同爲一個字符串更加昂貴。但是,如果你正在做很多這樣的事情,那麼很可能找到解決你的特殊問題的方法,這些問題更便宜。

但最終的結果將是,原來的問題的海報:是的,字符串是在Haskell效率不高,但相當得心應手。如果您擔心效率問題,請使用ByteStrings,並根據您的目的(ASCII/ISO-8859-1與某種Unicode或只是任意二進制數據)查看它們作爲Char8或Word8數組。一般來說,除非你知道你爲什麼需要非懶惰的東西(這通常是爲了評估懶惰評估的性能方面),否則使用Lazy ByteStrings(在字符串的開頭預先確定是一個非常快的操作)。

對於它的價值,我完全哈斯凱爾大廈的自動交易系統,以及我們需要做的是非常迅速地分析市場數據反饋,我們的事情一個接收通過網絡連接。我可以用一個可忽略不計的CPU來處理讀取和解析每秒300條消息;就處理這些數據而言,GHC編譯的Haskell對C的執行性能足夠接近,無法進入我的重要問題列表。