在 Python 中,我可以使用 yield
来构建列表,而无需定义临时变量:
def get_chars_skipping_bar(word):
while word:
# Imperative logic which can't be
# replaced with a for loop.
if word[:3] == 'bar':
word = word[3:]
else:
yield foo[0]
foo = foo[1:]
在 elisp 中,我看不到有任何方法可以做到这一点,无论是内置的还是使用任何预先存在的库。我不得不手动建立一个列表并对其调用 nreverse
。由于这是一种常见模式,我编写了自己的宏:
(require 'dash)
(require 'cl)
(defun replace-calls (form x func)
"Replace all calls to X (a symbol) in FORM,
calling FUNC to generate the replacement."
(--map
(cond
((consp it)
(if (eq (car it) x)
(funcall func it)
(replace-calls it x func)))
(:else it))
form))
(defmacro with-results (&rest body)
"Execute BODY, which may contain forms (yield foo).
Return a list built up from all the values passed to yield."
(let ((results (gensym "results")))
`(let ((,results (list)))
,@(replace-calls body 'yield
(lambda (form) `(push ,(second form) ,results)))
(nreverse ,results))))
示例用法:
(setq foo "barbazbarbarbiz")
(with-results
(while (not (s-equals? "" foo))
;; Imperative logic which can't be replaced with cl-loop's across.
(if (s-starts-with? "bar" foo)
(setq foo (substring foo 3))
(progn
(yield (substring foo 0 1))
(setq foo (substring foo 1))))))
在 elisp、cl.el 或库中一定有更好的方法或现有解决方案。
最佳答案
Python 函数实际上是一个生成器。在 ANSI Common Lisp 中,我们通常会使用词法闭包来模拟生成器,或者使用库来直接定义生成器,例如 Pygen。 .也许这些方法可以移植到 Emacs Lisp。
关于macros - 是否有用于构建列表的现有 lisp 宏?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23918121/