我是 haskell 的新手,我遇到了一个非常严重的性能问题,它必须是我的代码而不是 haskell 平台。
我有一个 Levenshtein 距离(自己的代码)的 python 实现,我将它传递(或尝试这样做)到 haskell。结果如下:
bool2int :: Bool -> Int
bool2int True = 1
bool2int False = 0
levenshtein :: Eq a => [a] -> [a] -> Int -> Int -> Int
levenshtein u v 0 0 = 0
levenshtein u v i 0 = i
levenshtein u v 0 j = j
levenshtein u v i j = minimum [1 + levenshtein u v i (j - 1),
1 + levenshtein u v (i - 1) j,
bool2int (u !! (i - 1) /= v !! (j - 1) ) + levenshtein u v (i - 1) (j - 1) ]
distance :: Eq a => [a] -> [a] -> Int
distance u v = levenshtein u v (length u) (length v)
现在,长度为 10 或更长的字符串的执行时间差异在 python 和 haskell 之间是 10 的各种幂。此外,通过一些粗略的时间测量(挂钟,因为到目前为止我还没有在 haskell 中找到 clock() 命令),我的 haskell 实现似乎没有花费 O(mn),但是其他一些快速增长的成本。
注意:我不希望我的 haskell 实现与 python 脚本竞争速度。我只是希望它在“合理”的时间内运行,而不是整个宇宙存在的时间的倍数。
问题:
- 我做错了什么,我的实现是如此的慢?
- 如何解决?
- 谈论“懒惰评估”:我认为如果
levenshtein "cat" "kit" 2 2
被调用三次,则只计算一次。这是正确的吗? - 我的 bool2int 必须有内置的东西,对吧?
- 如果任何其他意见能推动我在掌握 Haskell 的艰难道路上前进,我们将不胜感激。
编辑:这是用于比较的python代码:
#! /usr/bin/python3.2
# -*- coding, utf-8 -*-
class Levenshtein:
def __init__ (self, u, v):
self.__u = ' ' + u
self.__v = ' ' + v
self.__D = [ [None for x in self.__u] for x in self.__v]
for x, _ in enumerate (self.__u): self.__D [0] [x] = x
for x, _ in enumerate (self.__v): self.__D [x] [0] = x
@property
def distance (self):
return self.__getD (len (self.__v) - 1, len (self.__u) - 1)
def __getD (self, i, j):
if self.__D [i] [j] != None: return self.__D [i] [j]
self.__D [i] [j] = min ( [self.__getD (i - 1, j - 1) + (0 if self.__v [i] == self.__u [j] else 1),
self.__getD (i, j - 1) + 1,
self.__getD (i - 1, j) + 1] )
return self.__D [i] [j]
print (Levenshtein ('first string', 'second string').distance)