Scheme 从when语句中的函数返回

Scheme 从when语句中的函数返回,scheme,lisp,racket,Scheme,Lisp,Racket,我要做的就是使用when语句返回一个值:( 我想要以下功能: if(x) return y 我试着用: (when (x) y) 但是when语句的求值方式不是退出函数并返回y。它只是愉快地继续到下一行。有没有一种方法可以做到这一点而不造成外观非常难看的if-else块?mzscheme/racket不允许单臂ifs。您将其标记为Common Lisp和racket,这两种语言是完全不同的t语言。如果您正在使用Racket或Scheme并希望尽早从函数返回,则可以使用continua

我要做的就是使用when语句返回一个值:( 我想要以下功能:

if(x)
    return y
我试着用:

(when (x) y)

但是when语句的求值方式不是退出函数并返回y。它只是愉快地继续到下一行。有没有一种方法可以做到这一点而不造成外观非常难看的if-else块?mzscheme/racket不允许单臂ifs。

您将其标记为Common Lisp和racket,这两种语言是完全不同的t语言。如果您正在使用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在内的一些方案实现中,
当前延续调用
也绑定到
调用/cc
,但是
当前延续调用
是使用延续的唯一可移植方式

上述情况甚至比使用
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
宏,您可以在中找到它

编辑:提供了以下
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中,
(返回y)
仅在定义名为
nil
块时才会编译。某些表单隐式定义名为
nil
的块,例如
循环
宏。如果没有名为
nil
的块,您仍然可以使用
返回自
从命名块返回。如果您在使用
defun>定义的函数中
,该函数的名称也是包装该函数的块的名称,因此这将起作用:

(defun my-function (x y)
   (when x (return-from my-function y))
   ;;; more code
   )

球拍的一个简单方法:

(define (foo x)
  (let/ec return
    (when (= x 0)
       (return 'zero))
    'not-zero))
这里ec代表转义连续体,它比完整连续体便宜。

好吧,我将成为“那个家伙”;有一个很好的理由使用“极其丑陋”的解决方案,将函数的其余部分放在“else”中它使代码更容易阅读和理解。当我试图理解一个函数的功能时,我不想扫描所有的代码,寻找隐藏的
返回和奇怪的控制流。一个简单的“if”或“cond”可以非常清楚地说明在什么情况下将使用每段代码。

如果你仔细想想为什么你喜欢“when+return”解决方案,我怀疑在某种程度上,你想采取这种防范措施,让它远离你的认知过程,让函数的其余部分成为焦点。这(我声称)是产生微妙错误的秘诀

搜索你的感觉,你知道这是真的

编辑:一只蚂蚁刚刚爬过我的笔记本电脑。这表明我说的是实话。

简单:

(and (x) y)

问题是“when”不返回值。“and”是的。

x
的计算结果为
#f
时,代码应该怎么做?我认为这是一个XY问题。如果你想在
x
为真时退出函数,然后继续,否则你就有了If的定义。为什么你要通过所有这些限制来获取
返回的标识符类似的东西在R6RS中很好用。我遗漏了什么吗?@leppie没有。你没有遗漏任何东西。我实际上不知道你能做到。在Racket中,赋予宏内部特殊关键字含义的适当方法是使用语法参数。
(define syntax parameter return#f)(define syntax rule(define/return header body…+)(定义标题(let/ec返回延续(语法参数化([return(make rename transformer#'return-continuation)])body…)
这避免了破坏卫生或需要使用
语法大小写
/
语法解析
而不是更简单的
定义语法规则
@Jack语法参数可以被局部变量隐藏,使其不比全局变量更好。我详细介绍了它。@throwawayaccount 300万为什么能够阴影语法参数是一件坏事?这意味着它们尊重词法范围。如果我这样做了
(拼接let([return other])(define/return…)
我希望
return
引用范围内最接近的return定义。语法参数不用于将宏与某个全局标识符绑定,它们用于明确宏依赖于某个上下文绑定。而词汇范围的绑定是最容易推理的绑定。不,这是错误的不幸的是,在这个问题的上下文中,两者都做了相同的事情——都“愉快地继续到下一个[代码]行”,并且不会立即从函数返回。