在循环宏中使用回指绑定

时间:2017-11-21 14:22:46

标签: loops common-lisp hashtable

我有这样的结构

(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),例如,使用照应宏?

3 个答案:

答案 0 :(得分:4)

您是否只想尝试那些已经在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)))

答案 1 :(得分:2)

您通常也可以使用#=##来避免重复:

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

这是在读取时插入代码。

答案 2 :(得分:1)

为了完整性,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)))))

请注意,如果您经常访问/修改相同的哈希表,那么定义一个全局宏来隐藏实现细节可能是个好主意。

另外,你甚至可以使用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)))))