How to Write a Spelling Corrector (Clojure 版)

※恥ずかしい綴り間違い修正。collect=> correct

Clojure ML より。(前も話題になっていたかも)

http://norvig.com/spell-correct.html "How to Write a Spelling Corrector" に Clojure で Spelling Corrector を書いた例(のリンク)が追加されている。Python 版、Scheme 版、Ruby 版などと比べて最短となっているようだ。まだ全然読んでいないけどこれから読むはずのコードがこれ。これが Shiro さんによる scheme 版と何が違っているのか、は解読してみる価値があるかもしれない。
clojure の max-key, distinct が組み込みなのは「ずるい」といって良いかもしれないけれど、Python 版と同程度以上に「見やすい」気がするのは注目。

(defn words [text] (re-seq #"[a-z]+" (.toLowerCase text)))
 
(defn train [features]
  (reduce (fn [model f] (assoc model f (inc (get model f 1)))) {} features))
 
(def *nwords* (train (words (slurp "big.txt"))))
 
(defn edits1 [word]
  (let [alphabet "abcdefghijklmnopqrstuvwxyz", n (count word)]
    (distinct (concat
      (for [i (range n)] (str (subs word 0 i) (subs word (inc i))))
      (for [i (range (dec n))]
        (str (subs word 0 i) (nth word (inc i)) (nth word i) (subs word (+ 2 i))))
      (for [i (range n) c alphabet] (str (subs word 0 i) c (subs word (inc i))))
      (for [i (range (inc n)) c alphabet] (str (subs word 0 i) c (subs word i)))))))
 
(defn known [words nwords] (for [w words :when (nwords w)]  w))
 
(defn known-edits2 [word nwords] (for [e1 (edits1 word) e2 (edits1 e1) :when (nwords e2)]  e2))
 
(defn correct [word nwords]
  (let [candidates (or (known [word] nwords) (known (edits1 word) nwords) 
                       (known-edits2 word nwords) [word])]
    (apply max-key #(get nwords % 1) candidates)))