Lets say I wanted to implement the usual dynamic programming algorithm for Levensthein distance (edit distance). It is quite easy to come up with the recursion:
editDistance [] ys = length ys
editDistance xs [] = length xs
editDistance (x:xs) (y:ys)
| x == y = editDistance xs ys
| otherwise = minimum [
1 + editDistance xs (y:ys),
1 + editDistance (x:xs) ys,
1 + editDistance xs ys]
This suffers from exponential running time, so it is necessary to memoize the function. I want to do so by using Data.Memocombinators, and I have tried several ways. Here is my current attempt:
import qualified Data.MemoCombinators as M
memLength str =
M.wrap
(\i -> drop i str)
(\xs -> length str - length xs)
(M.arrayRange (0,length str))
elm xs ys = (M.memo2 memListx memListy editDistance) xs ys
where
memListx = memLength xs
memListy = memLength ys
However, the memoization seems not to have any effect, although I would expect any memoization to have a noticeable improvement to running time since it would at least be polynomial. What is wrong with my implementation? How can I get an ok running time while preserving as much as possible of the high level definition of edit distance?