首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在Lisp中实现redo语句(如Perl和Ruby)

如何在Lisp中实现redo语句(如Perl和Ruby)
EN

Stack Overflow用户
提问于 2013-06-28 16:53:46
回答 2查看 250关注 0票数 4

需要其他语言的break语句或continue语句的代码可以使用Common Lisp和Emacs Lisp中的block & return-fromcatch & throw来完成。然后是需要redo语句的代码,或者至少最好用redo编写。而且redo语句不必是关于循环的。我如何在Lisp语言中做redo

如果在Lisp中有一个等同于redo的东西,我想它应该是这样工作的:接受符号和表单的特殊形式with-redo,以及接受符号的redo。form (with-redo 'foo BODY-FORMS...)可以在其BODY-FORMS中包含(redo 'foo),并且(redo 'foo)将控制权转移回BODY-FORMS的开头。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-06-28 17:06:35

在Common Lisp中:

代码语言:javascript
复制
(tagbody
   start
   (do-something)
   (go start))


(dotimes (i some-list)
  redo
  (when (some-condition-p)
    (go redo))
  (some-more))
票数 7
EN

Stack Overflow用户

发布于 2013-06-29 17:57:35

更新:Emacs24.4(即将发布)有标记体。Emacs24.4附带的cl-lib包括cl-tagbody.

对于没有标记体的Lisp方言,只要该方言有一个捕获/抛出等效项,就仍然可以实现redo。

对于Emacs Lisp:

代码语言:javascript
复制
;; with-redo version 0.1
(defmacro with-redo (tag &rest body)
  "Eval BODY allowing jumps using `throw'.
TAG is evalled to get the tag to use; it must not be nil.
Then the BODY is executed.
Within BODY, a call to `throw' with the same TAG and a non-nil VALUE causes a jump to the beginning of BODY.
A call to `throw' with the same TAG and nil as VALUE exits BODY and this `with-redo'.
If no throw happens, `with-redo' returns the value of the last BODY form."
  (declare (indent 1))
  (let ((ret (make-symbol "retval")))
    `(let (,ret)
       (while
           (catch ,tag
             (setq ,ret (progn ,@body))
             nil))
       ,ret)))
(defun redo (symbol)
  (throw symbol t))

使用示例(所有示例都用Emacs Lisp编写):

代码语言:javascript
复制
(with-redo 'question
  (let ((name (read-string "What is your name? ")))
    (when (equal name "")
      (message "Zero length input. Please try again.")
      (beep)
      (sit-for 1)
      (redo 'question))
    name))

以中间测试循环的形式编写相同的示例:

代码语言:javascript
复制
(require 'cl-lib)
(let (name)
  (cl-loop do
           (setq name (read-string "What is your name? "))
           while
           (equal name "")
           do
           (message "Zero length input. Please try again.")
           (beep)
           (sit-for 1))
  name)

同样的例子写成了一个无限循环,但却抛出了:

代码语言:javascript
复制
(let (name)
  (catch 'question
    (while t
      (setq name (read-string "What is your name? "))
      (unless (equal name "")
        (throw 'question name))
      (message "Zero length input. Please try again.")
      (beep)
      (sit-for 1))))

实现with-lex-redo-anonlex-redo,其中(lex-redo)会跳转到文本/词法上最内层的with-lex-redo-anon表单的正文开头:

代码语言:javascript
复制
;; with-lex-redo-anon version 0.1
(require 'cl-lib)
(defmacro with-lex-redo-anon (&rest body)
  "Use with `(lex-redo)'."
  (let ((tag (make-symbol "lex-redo-tag"))
        (ret (make-symbol "retval")))
    `(cl-macrolet ((lex-redo () '(cl-return-from ,tag t)))
       (let (,ret)
         (while
             (cl-block ,tag
               (setq ,ret (progn ,@body))
               nil))
         ,ret))))

示例测试:

代码语言:javascript
复制
(let ((i 0) (j 0))
  (with-lex-redo-anon
    (with-lex-redo-anon
      (print (list i j))
      (when (< j 2)
        (incf j)
        (lex-redo)))
    (when (< i 2)
      (incf i)
      (lex-redo))))

与另一个答案中的输出相同。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17360847

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档