繁体   English   中英

为什么Haskell代码这么慢?

[英]Why is this Haskell code so slow?

我对Haskell有点陌生,并尝试制作拼字游戏求解器。 它接收您当前拥有的字母,找到它们的所有排列并过滤掉那些字典词。 代码很简单:

import Data.List

main = do
    dict    <- readFile "words"
    letters <- getLine
    let dictWords = words dict
    let perms = permutations letters
    print [x | x <- perms, x `elem` dictWords]

但是,与我使用Python的非常相似的实现相比,它的速度非常慢。 我做错了什么基本的事情吗?

*编辑:这是我的Python代码:

from itertools import permutations

letters = raw_input("please enter your letters (without spaces): ")

d = open('words')
dictionary = [line.rstrip('\n') for line in d.readlines()]
d.close()

perms = ["".join(p) for p in permutations(letters)]

validWords = []

for p in perms:
    if p in dictionary: validWords.append(p)


for validWord in validWords:
    print validWord

我没有对它们进行精确计时,但是大致感觉像是Python实现的速度大约是Haskell的两倍。 相比之下,也许我不应该说Haskell代码“慢得令人难以置信”,但是由于Haskell是静态类型的,我想我只是认为它应该快得多,而不比Python慢​​。

我对Haskell有点陌生,并尝试制作拼字游戏求解器。

通过使用更好的算法,您可以大大改善事情。

如果不对输入字母的每个排列进行测试,而是先对其进行排序,则只能进行一次字典查找,并获取由它们形成的所有可能的单词(字谜)(使用所有单词)。

这是将该字典创建为Data.Map的代码。 创建地图会产生启动费用,但是在第一个查询之后,后续查找非常快。

import Data.List
import qualified Data.Map.Strict as Map
import Control.Monad
import System.IO

main = do
  contents <- readFile "words"
  let pairs = [ (sort w, [w]) | w <- words contents ]
      dict = foldl' (\m (k,v) -> Map.insertWith (++) k v m) Map.empty pairs
      -- dict = foldr (\(k,v) m -> Map.insertWith (++) k v m) Map.empty pairs
  forever $ do
    putStr "Enter letters: " >> hFlush stdout
    letters <- getLine
    case Map.lookup (sort letters) dict of
      Nothing -> putStrLn "No words."
      Just ws -> putStrLn $ "Words: " ++ show ws

236K字(2.5 MB)的字文件的地图创建时间约为4-5秒。 通过使用ByteStrings或Text而不是String,可能会实现更好的性能。

尝试一些好的字母组合:

steer rat tuna lapse groan neat

注意:使用GHC 7.10.2,我发现此代码在使用-O2进行编译的情况下表现最佳。

检查x是否是dictWords的元素可能很慢。 我会假设您的类似python实现在一组或排序的向量中存储dictWords (在后一种情况下使用二进制搜索)? 似乎您可能要在这里做同样的事情。

使用此单词列表和下面的代码,Python版本运行约30秒,而Haskell版本则需要1.5分钟。 因此,Haskell速度较慢(也许是因为它使用的是链表,在所有条件都相同的情况下,迭代速度较慢),但是与Python相比,我不会将其称为“异常慢”。 切换为使用任一版本中的集可将时间减少到1秒以下。

from itertools import permutations
f = open('twl06.txt')
words = f.read().split()

print [''.join(p) for p in permutations('apricot') if ''.join(p) in words]

这是基于集合的Haskell代码:

import Data.Set
import Data.List

main = do
    dict    <- readFile "twl06.txt"
    let letters = "apricot"
    let dictWords = Data.Set.fromList $ words dict
    let perms = permutations letters
    print [x | x <- perms, member x dictWords]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM