【发布时间】:2015-07-29 10:28:17
【问题描述】:
我正在尝试编写代码以在 Haskell 中执行以下简单任务:使用该字典查找单词的词源,该字典存储为一个大的 tsv 文件 (http://www1.icsi.berkeley.edu/~demelo/etymwn/)。我想我会(使用 attoparsec)将 tsv 文件解析为一个 Map,然后我可以根据需要使用它来有效地查找词源(并做一些其他的事情)。
这是我的代码:
{-# LANGUAGE OverloadedStrings #-}
import Control.Arrow
import qualified Data.Map as M
import Control.Applicative
import qualified Data.Text as DT
import qualified Data.Text.Lazy.IO as DTLIO
import qualified Data.Text.Lazy as DTL
import qualified Data.Attoparsec.Text.Lazy as ATL
import Data.Monoid
text = do
x <- DTLIO.readFile "../../../../etymwn.tsv"
return $ DTL.take 10000 x
--parsers
wordpair = do
x <- ATL.takeTill (== ':')
ATL.char ':' *> (ATL.many' $ ATL.char ' ')
y <- ATL.takeTill (\x -> x `elem` ['\t','\n'])
ATL.char '\n' <|> ATL.char '\t'
return (x,y)
--line of file
line = do
a <- (ATL.count 3 wordpair)
case (rel (a !! 2)) of
True -> return . (\[a,b,c] -> [(a,c)]) $ a
False -> return . (\[a,b,c] -> [(c,a)]) $ a
where rel x = if x == ("rel","etymological_origin_of") then False else True
tsv = do
x <- ATL.many1 line
return $ fmap M.fromList x
main = (putStrLn . show . ATL.parse tsv) =<< text
它适用于少量输入,但很快就会变得太低效。我不太清楚问题出在哪里,并且很快意识到即使是像查看文件的最后一个字符这样的琐碎任务,在我尝试时也会花费太长时间,例如与
foo = fmap DTL.last $ DTLIO.readFile "../../../../etymwn.tsv
所以我的问题是:在方法和执行方面,我主要做错了什么?有关更多 Haskelly/更好代码的任何提示?
谢谢,
鲁本
【问题讨论】:
-
如果您正在阅读的文件太大,减少程序启动时间的一个不错的选择是将文件的内容移动到数据库中(嵌入或不嵌入)。一旦在数据库中建立索引,就可以直接进行随机查找,而无需先顺序读取文件。
-
除了分析之外,我建议您阅读这份关于性能注意事项的简短指南:hackage.haskell.org/package/attoparsec-0.13.0.1/docs/…
-
我只是在这里猜测:解析器可能需要扫描整个文件以选择是返回成功值还是返回失败值。 IE。
ATL.many1可能不会那么懒惰,无论如何都会强制将所有内容都保存在内存中。
标签: performance haskell io hashmap attoparsec