Я играю с расчетом Левенштейновских расстояний в Хаскеле, и немного разочарован следующей проблемой производительности.Если вы реализуете это наиболее «нормальным» способом для Haskell, как показано ниже (dist), все работает просто отлично:
dist :: (Ord a) => [a] -> [a] -> Int
dist s1 s2 = ldist s1 s2 (L.length s1, L.length s2)
ldist :: (Ord a) => [a] -> [a] -> (Int, Int) -> Int
ldist _ _ (0, 0) = 0
ldist _ _ (i, 0) = i
ldist _ _ (0, j) = j
ldist s1 s2 (i+1, j+1) = output
where output | (s1!!(i)) == (s2!!(j)) = ldist s1 s2 (i, j)
| otherwise = 1 + L.minimum [ldist s1 s2 (i, j)
, ldist s1 s2 (i+1, j)
, ldist s1 s2 (i, j+1)]
Но, если вы немного согните свой мозг и внедрите его как dist ', он выполнится НАМНОГО быстрее (примерно в 10 раз).
dist' :: (Ord a) => [a] -> [a] -> Int
dist' o1 o2 = (levenDist o1 o2 [[]])!!0!!0
levenDist :: (Ord a) => [a] -> [a] -> [[Int]] -> [[Int]]
levenDist s1 s2 arr@([[]]) = levenDist s1 s2 [[0]]
levenDist s1 s2 arr@([]:xs) = levenDist s1 s2 ([(L.length arr) -1]:xs)
levenDist s1 s2 arr@(x:xs) = let
n1 = L.length s1
n2 = L.length s2
n_i = L.length arr
n_j = L.length x
match | (s2!!(n_j-1) == s1!!(n_i-2)) = True | otherwise = False
minCost = if match then (xs!!0)!!(n2 - n_j + 1)
else L.minimum [(1 + (xs!!0)!!(n2 - n_j + 1))
, (1 + (xs!!0)!!(n2 - n_j + 0))
, (1 + (x!!0))
]
dist | (n_i > n1) && (n_j > n2) = arr
| n_j > n2 = []:arr `seq` levenDist s1 s2 $ []:arr
| n_i == 1 = (n_j:x):xs `seq` levenDist s1 s2 $ (n_j:x):xs
| otherwise = (minCost:x):xs `seq` levenDist s1 s2 $ (minCost:x):xs
in dist
Я попробовал все обычные трюки seq
в первой версии, но, похоже, ничего не ускорило.Это немного неудовлетворительно для меня, потому что я ожидал, что первая версия будет на быстрее , потому что не нужно оценивать всю матрицу, только те части, которые ей нужны.
Кто-нибудь знает, возможно ли заставить эти две реализации работать одинаково, или я просто пожинаю преимущества оптимизации хвостовой рекурсии в последнем, и поэтому мне нужно жить с его нечитаемостью, если я хочу производительности?
Спасибо, Орион