implementiert I Levenshtein Entfernung in einem ziemlich Standard Art und Weise in F # als eine ÜbungSchwanz rekursive Levenshtein Entfernung
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
])
Allerdings habe ich nicht eine einfache Art und Weise finden Sie in der List.min Aufruf zu konvertieren Schwanz rekursiv zu sein. Wir machen nicht einfach einige zusätzliche, unabhängige Berechnungen nach dem rekursiven Aufruf; Stattdessen wählen wir das Ergebnis mehrerer rekursiver Aufrufe.
Gibt es eine Möglichkeit, dies elegant umzuwandeln, um rekursiv zu sein?
(Ich kann leicht den +1
konvertieren Schwanz rekursiv zu sein)
I denke ich sehe eine Lösung ... aber es scheint super verschlungen. Anstatt levdist dreimal aufzurufen und dann die min zu nehmen, können wir levdist mit (alen-1 blen) aufrufen und eine Fortsetzung weiterleiten, die levdist (alen blen-1) aufruft, und so fort. Die min op wird in den Fortsetzungen gemacht. – jameszhao00
Ich würde mir nicht allzu viele Gedanken darüber machen, wie es rekursiv wird - Ihr Algorithmus scheint exponentielle Arbeit zu erfordern, so dass Sie nie Gefahr laufen, den Stack zu überlaufen. – kvb
Nur als Übung :) Sie können diese (nicht tail-rekursive) Funktion als n * m (n^2 ish) memotisieren. – jameszhao00