## Spell Checking

### April 17, 2009

Our word list will be stored in a trie that provides t-null for the empty trie, t-look to determine if word is in the trie, and t-bind to bind a new word to the trie. The branches of the trie are stored in association lists, but instead of the standard Scheme a-lists we use our own, in which characters are stored in sorted order. All comparisons are case-insensitive. First the a-list functions:

(define a-null '())

(define (a-look c a)
(cond ((null? a) #f)
((char-ci<? c (caar a)) #f)
((char-ci<? (caar a) c) (a-look c (cdr a)))
(else (car a))))

(define (a-bind c x a)
(cond ((null? a) (list (cons c x)))
((char-ci<? c (caar a)) (cons (cons c x) a))
((char-ci<? (caar a) c) (cons (car a) (a-bind c x (cdr a))))
(else (cons (cons c x) (cdr a)))))

A trie is a pair consisting of a value and an a-list of successors. The value is boxed in a list, so '() indicates no-value and '(x) indicates the value x. The null trie conses the null list to the null a-list:

(define t-null (cons '() a-null))

Trie lookup goes one character at a time. There are two ways for lookup to fail: if the end of the key finds a '() value, or if an intermediate node does not exist:

(define (t-look ks t)
(if (null? ks)
(if (pair? (car t)) (caar t) #f)
(let ((x (a-look (car ks) (cdr t))))
(if x (t-look (cdr ks) (cdr x))#f))))

Adding or replacing a value in a trie is similar to lookup, except that it never fails; if necessary, the trie is extended with a null node:

(define (t-bind ks x t)
(if (null? ks) (cons (list x) (cdr t))
(let* ((a1 (a-look (car ks) (cdr t)))
(t2 (t-bind (cdr ks) x (if (pair? a1) (cdr a1) t-null))))
(cons (car t) (a-bind (car ks) t2 (cdr t))))))

Make-dict reads a word list, one word per line, binding each word to #t; read-line comes from the Standard Prelude:

(define (make-dict filename)
(with-input-from-file filename
(lambda ()
(let loop ((word (read-line)) (dict t-null))
(if (eof-object? word) dict
(loop (read-line) (t-bind (string->list word) #t dict)))))))

The dictionary is loaded from the standard word list:

(define dict (make-dict "/usr/dict/words"))

Spell-checking a word is done by submitting the key to the dictionary:

(define (spell word)
(t-look (string->list word) dict))

Programming is spelled correctly, but my dictionary thinks praxis is somehow akin to cwm:

> (spell "Programming")
#t
> (spell "Praxis")
#f

You can see the program at http://codepad.org/fK2CUpEQ.

Pages: 1 2

### 4 Responses to “Spell Checking”

1. FalconNL said

import qualified Data.ByteString.Char8 as B
import Data.Trie

main = do trie <- fmap (fromList . map (flip (,) ()) . B.lines) \$ B.readFile "words.txt"
print \$ valid trie "qarter"

valid trie = flip member trie . B.pack

2. veer said

In scheme :

3. Vikas Tandi said

implemented in c language: