哈斯克尔:我可以使用懒惰来及早退出#34;并获得表现?

时间:2015-04-11 04:34:19

标签: haskell optimization lazy-evaluation

我正在编写一个Haskell程序,该程序读取英语单词列表和矩形字母网格,如:

I T O L
I H W S
N H I S
K T S I

然后从左上角通过网格找到一个Hamiltonian path,用于拼出一系列英文单词,例如:

--> $ runghc unpacking.hs < 4x4grid.txt
I THINK THIS IS SLOW

(如果有多个解决方案,它可以打印任何找到的解决方案并停止查找。)

天真,严格的方法是生成一条完整的路径,然后尝试将其拆分为单词。但是,假设我正在这样做(目前我正在强迫自己 - 见下文),我花了很多时间寻找路径:

IINHHTOL...
IINHHTOW...
IINHHWOL...

这些显然永远不会变成文字,看着前几个字母("IINH"不能分成单词,而且没有英文单词包含"NHH"。)所以,说,在上面的网格中,我不想查看以IINHH开头的许多 [1] 路径。

现在,我的功能看起来像这样:

paths :: Coord -> Coord -> [[Coord]]
paths (w, h) (1, 1) = [[(1, 1), (1, 2), ... (x, y)], ...]

lexes :: Set String -> String -> [[String]]
lexes englishWordset "ITHINKTHISWILLWORK" = [["I", "THINK", "THIS", ...], ...]

paths只是在(w, h)网格上找到值得考虑的所有路径。 lexes找到了删除短语的所有方法,并定义为:

lexes language [] = [[]]
lexes language phrase = let
  splits = tail $ zip (inits phrase) (tails phrase)
  in concat [map (w:) (lexes language p') | (w, p') <- splits,
             w `S.member` language]

鉴于"SAMPLESTRING",它会查看"S",然后是"SA",然后是"SAM" ...一旦找到有效字,它会递归并尝试“ lex“其余的字符串。 (首先它会在"PLESTRING"上递归并尝试用"SAM"制作短语,但是找不到将“plestring”剁成单词并失败的方法;然后它会找到["SAMPLE", "STRING"]。)

当然,对于上面的无效字符串,遵循这种方法会失去任何“懒惰”的希望:在前面的示例中,我们仍然需要搜索超出像"ITOLSHINHISIST"这样荒谬的短语,因为可能{ {1}}(一个字母更长)可能形成有效的单个字。

我觉得我可以在某种程度上使用懒惰来提高整个程序的性能:如果"ITOLSHINHISISTK"的前几个字符不是任何字的前缀,我们可以保释完全退出,停止评估phrase的其余部分,以及剩余的路径。 [2] 这是否有意义?是否有一些树状的数据结构可以帮助我检查不是集合成员资格,但设置“prefix-ness”,从而使检查有效性变得更加懒惰?

[1]显然,对于一个4x4网格,其中很少有这些,但这个论点是关于一般情况:对于更大的网格,我可以跳过成千上万的路径,我看到他们开始时“剑侠情缘”。 对于从输入文件中读取的某些phrase phrase,[2] map (grid M.!) path仅为Map Coord Char

0 个答案:

没有答案