I wdrożone Odległość Levenshteina w dość standardowy sposób w F # jako ćwiczenieTail Recursive Levenshteina Odległość
let lastchar (s:string) = s.Substring(s.Length-1, 1)
let lastchar_substring (s:string) len = s.Substring(len-1, 1)
let rec levdist (sa:string) (sb:string) alen blen = match alen, blen with
| -1, -1 -> levdist sa sb sa.Length sb.Length
| 0, 0 -> 0
| _ , 0 -> alen
| 0, _ -> blen
| _ -> List.min [ (* How do I make this tail recursive...? *)
(levdist sa sb (alen-1) blen) + 1;
(levdist sa sb alen (blen-1)) + 1;
(levdist sa sb (alen-1) (blen-1)) +
match (lastchar_substring sa alen), (lastchar_substring sb blen) with
| x, y when x = y -> 0
| _ -> 1
])
Jednak nie widzę prosty sposób przekonwertować rozmowę List.min za ogon rekurencyjnej. Nie wykonujemy po prostu dodatkowych, niezależnych obliczeń po wywołaniu rekursywnym; zamiast tego wybieramy wynik wielu wywołań rekurencyjnych.
Czy istnieje sposób, aby elegancko przekonwertować to na rekursywne?
(można łatwo przekonwertować +1
za ogon rekurencyjnej)
I myślę, że widzę rozwiązanie ... ale wydaje się to bardzo zawiłe. Zamiast trzykrotnie wywołać levdist, a następnie przyjąć min, możemy nazwać levdist (alen-1 blen) i przekazać mu jakąś kontynuację, która nazywa levdist (alen blen-1), i tak dalej. Min op zostanie wykonany w kontynuacji. – jameszhao00
Nie martwiłbym się zbytnio o to, aby uczynić go rekurencyjnym - Twój algorytm wydaje się wymagać pracy wykładniczej, więc nigdy nie będziesz w niebezpieczeństwie przepełnienia stosu. – kvb
Podobnie jak ćwiczenie :) Możesz zapamiętać tę funkcję (nie rekurencyjną), aby n * m (n^2 ish). – jameszhao00