% Macro WITH-HASH-TABLE-ITERATOR
Macro WITH-HASH-TABLE-ITERATOR
with-hash-table-iterator
(name hash-table) declaration* form*
=> result*
name - macrolet
の最初の引数として適切な名前
hash-table - フォーム。
一度だけ評価され、ハッシュテーブルを生成しなければなりません。
declaration - 宣言式。評価されません。
form - 暗黙のprogn
result - formの返却値
ボディ部のレキシカルスコープ内で
nameがmacrolet
によって定義され、
連続した(name)
の実行は、
ハッシュテーブルからの要素がひとつひとつ返却されます。
ハッシュテーブルはhash-tableが一度だけ評価されることによって得られます。
(name)
の実行は、下記に示す3つの値が返却されます。
連続した(name)
の実行によって
全てのエントリーが返却された後は、
ただひとつだけの値nil
が返却されます。
もし繰り返しの何らかの暗黙的な内部状態が
クロージャーで起動フォームを囲んだ返却値などによって
with-hash-table-iterator
フォームの
動的エクステントの外側で返却されたときに
何が起こるかは指定されていません。
with-hash-table-iterator
はいくつでもネストすることが可能であり、
もっとも内側のボディ部は、
これら全てのマクロが違う名前を持っているようなときは、
確立されたローカルマクロの全てを起動することができます。
下記の関数はどんなハッシュテーブルでもt
を返却し、
もしwith-hash-table-iterator
の使用が、
対応するmaphash
の使用に合っていないときはエラーが発生します。
(defun test-hash-table-iterator (hash-table)
(let ((all-entries '())
(generated-entries '())
(unique (list nil)))
(maphash #'(lambda (key value) (push (list key value) all-entries))
hash-table)
(with-hash-table-iterator (generator-fn hash-table)
(loop
(multiple-value-bind (more? key value) (generator-fn)
(unless more? (return))
(unless (eql value (gethash key hash-table unique))
(error "Key ~S not found for value ~S" key value))
(push (list key value) generated-entries))))
(unless (= (length all-entries)
(length generated-entries)
(length (union all-entries generated-entries
:key #'car :test (hash-table-test hash-table))))
(error "Generated entries and Maphash entries don't correspond"))
t))
下記のものはwith-hash-table-iterator
によって実装された、
適切なmaphash
の定義です。
(defun maphash (function hash-table)
(with-hash-table-iterator (next-entry hash-table)
(loop (multiple-value-bind (more key value) (next-entry)
(unless more (return nil))
(funcall function key value)))))
なし。
なし。
with-hash-table-iterator
によって確立された
nameというローカル関数は、
それが第一返却値としてfalseを返却したあとに
呼び出された結果は未定義です。
3.6. 横断の規則と副作用
なし。