LOOP マクロのコツ

LOOP マクロを使うとき、わたしはつい、以下のように書いてしまう。

(defun parse-grid (grid)
  "テキスト形式 grid を可能な値のハッシュテーブルに変換する。
square => digits
ただし矛盾が見つかった場合は nil を返す。"
  (let ((values (make-hash-table)))
    (loop for s in squares do (setf (gethash s values) digits))
    (loop for s being the hash-keys in (grid-values grid)
       using (hash-value d)
       if (and (member d digits) (not (assign values s d)))
       do (return nil)
       finally (return values))))

この形は、let の中に loop が書いてある。これだと関数の本体は、let 式だ。こうではなく、LOOP が関数の本体になるように書くと、下のようにより簡潔になって、良いと思う。

(defun parse-grid (grid)
  "テキスト形式 grid を可能な値のハッシュテーブルに変換する。
square => digits
ただし矛盾が見つかった場合は nil を返す。"
  (loop with values = (make-hash-table)
     initially
       (loop for s in squares do (setf (gethash s values) digits))
     for s being the hash-keys in (grid-values grid)
     using (hash-value d)
     never (and (member d digits) (not (assign values s d)))
     finally (return values)))

ここでは with を使ってローカル変数を定義し、さらに initially を使って前処理を行っている。また return を一つ減らして、never を使うようにもした。