LOOP マクロでできないこと

残念ながら Common Lisp の LOOP マクロでもできないことがあるようだ。「あらゆる数独パズルを解く」の python のコードで、search という関数で見つけた。

def search(values):
    "深さ優先探索と制約伝播を使い、すべての可能なvaluesを試す。"
    if values is False:
        return False ## 前の時点で失敗している
    if all(len(values[s]) == 1 for s in squares): 
        return values ## 解けた!
    ## 取り得る値の個数が最小である未確定のマスsを選ぶ
    n,s = min((len(values[s]), s) for s in squares if len(values[s]) > 1)
    return some(search(assign(values.copy(), s, d)) 
		for d in values[s])

search 関数の下から3行目で、辞書の要素の長さが最小となる辞書のキー s とその長さ n(値としては捨てている) を一行で取得している。LOOP マクロには minimizing というのがあるが、これを使っても値しか取れない。調べたところ LOOP マクロではなく ITERATE マクロというのを使うとできるようだ。以下の例は、リストの長さを最大にする要素を取り出している。

;; http://items.sjbach.com/211/comparing-loop-and-iterate の *Finding* より
(iter (for lst in '((a) (b c d) (e f)))
      (finding lst maximizing (length lst)))
=> (B C D) 
 
;; The rough equivalent in LOOP:
(loop with max-lst = nil
      with max-key = 0
      for lst in '((a) (b c d) (e f))
      for key = (length lst)
      do
      (when (> key max-key)
        (setf max-lst lst
              max-key key))
      finally (return max-lst))
=> (B C D)