在循环宏中使用照应绑定

Using anaphoric bindings within a loop macro

我有这样的结构

(loop :for c :in list-of-char-codes
      :if (gethash c hash-of-frequencies)
        :do (incf (gethash c hash-of-frequencies) 0))

是否有合理的方法来避免冗余 (gethash c hash-of-frequencies),例如,使用照应宏?

您是否试图仅计算 hash-of-frequencies 中已经存在的那些字符?

(loop :for c :in list-of-char-codes
  :for freq = (gethash c hash-of-frequencies)
  :when freq
  :do (setf (gethash c hash-of-frequencies) (1+ freq)))

或者您可能想要计算 所有 个字符?

(loop :for c :in list-of-char-codes
  :do (incf (gethash c hash-of-frequencies 0)))

您通常也可以通过使用 #=## 来避免重复,就像这样:

(loop :for c :in list-of-char-codes
      :for freq = #1=(gethash c hash-of-frequencies)
      :when freq
        :do (setf #1# (1+ freq)))

这是在读取时插入代码。

完整性w.r.t。其他好的答案,你也可以这样做:

(defun foo (list-of-char-codes hash-of-frequencies)
  (macrolet ((hash (c) `(gethash ,c hash-of-frequencies)))
    (loop :for c :in list-of-char-codes
          :for freq = (hash c)
          :when freq
            :do (setf (hash c) (1+ freq)))))

请注意,如果您经常 access/modify 相同的散列 table,定义一个全局宏来隐藏实现细节可能是个好主意。

此外,您甚至可以使用 symbol-macrolet,但我认为这种风格很糟糕,因为下面会注入 c,使绑定隐含,并且在重命名变量 c 时会中断(虽然你问过照应宏):

;; AVOID DOING THAT, PLEASE
(defun foo (list-of-char-codes hash-of-frequencies)
  (symbol-macrolet ((hash (gethash c hash-of-frequencies)))
    (loop :for c :in list-of-char-codes
          :for freq = hash
          :when freq
            :do (setf hash (1+ freq)))))