您将其标记为 Common Lisp 和 Racket,它们是两种完全不同的语言。如果您正在使用 Racket 或 Scheme 并希望尽早从函数中返回,则可以使用 continuation:
(define (my-function x y)
(call-with-current-continuation
(lambda (return)
(when x (return y))
;; Rest of code not evaluated if X is true
)))
在包括 Racket 在内的一些 Scheme 实现中,call-with-current-continuation 也绑定到 call/cc,但 call-with-current-continuation 是使用延续的唯一可移植方式。
上面的内容比使用cond 语句还要难看。如果你想摆脱所有多余的废话,你可以定义一个宏来创建define 的替代版本,它会自动创建延续并将其绑定到return:
(define-syntax define/return
(syntax-rules ()
((_ (name . args) . body)
(define (name . args)
(capture-vars (return)
(call/cc (lambda (return) . body)))))))
这需要您拥有我的capture-vars 宏,您可以在this answer 中找到它。
编辑:Leppie 提供了define/return 的以下实现,这要简单得多,因为它不需要我的capture-vars 宏:
(define-syntax define/return
(lambda (x)
(syntax-case x ()
[(_ (name . args) . body)
(with-syntax
([return (datum->syntax #'name 'return)])
#'(define (name . args)
(call/cc (lambda (return) . body))))])))
编辑 2:但是,如果您将 define/return 合并到另一个宏中,则很容易以这种方式意外取消捕获 return 的定义。
然后return 将按照您的预期行事,并且不会在语法上令人反感:
(define/return (my-function x y)
(when x (return y))
;;; more code...
)
但是,如果您使用的是 Common Lisp,情况就不同了。在 Common Lisp 中,(return y) 只有在定义了名为 nil 的 block 时才会编译。某些形式隐式定义了一个名为nil 的块,例如loop 宏。如果没有名为 nil 的块,您仍然可以使用 return-from 从命名块返回。如果您在使用defun 定义的函数中,则该函数的名称也是包装该函数的块的名称,所以这会起作用:
(defun my-function (x y)
(when x (return-from my-function y))
;;; more code
)