Returning from a function inside when statement

巧了我就是萌 提交于 2019-12-10 14:23:24

问题


All I'm trying to do is use a when statement to return a value :( I want the functionality of:

if(x)
    return y

And I'm trying to use:

(when (x) y)

But the when statement is not evaluating in a way that exits the function and return y. It just happily carries on to the next line. Is there a way to do this without making an extremely ugly looking if-else block? mzscheme/racket does not allow 1-armed ifs.


回答1:


You tagged this as both Common Lisp and Racket, which are two completely different languages. If you're using Racket or Scheme and want to return from a function early, you can do it using a 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
      )))

In some Scheme implementations including Racket, call-with-current-continuation is also bound to call/cc, but call-with-current-continuation is the only portable way to use continuations.

The above is even uglier than using a cond statement. If you want to get rid of all that extra crap, you can define a macro that creates an alternate version of define that automatically creates the continuation and binds it to return:

(define-syntax define/return
   (syntax-rules ()
      ((_ (name . args) . body)
       (define (name . args)
         (capture-vars (return)
            (call/cc (lambda (return) . body)))))))

This requires you to have my capture-vars macro, which you can find in this answer.

EDIT: Leppie provided the following implementation of define/return which is much simpler since it doesn't require my capture-vars macro:

(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))))])))

EDIT 2: However, it's easy to accidentally un-capture the definition of return doing it this way, if you incorporate a define/return in another macro.

Then return will behave as you'd expect and not be syntactically repugnant:

(define/return (my-function x y)
    (when x (return y))
    ;;; more code...
)

However, if you're using Common Lisp, the situation is different. In Common Lisp, (return y) will only compile when a block named nil is defined. Certain forms implicitly define a block named nil, such as the loop macro. Without a block named nil, you can still use return-from to return from a named block. If you're in a function defined with defun, the name of that function is also the name of a block that wraps that function, so this would work:

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



回答2:


Okay,I'm going to be "that guy"; there's a good reason for using the "extremely ugly" solution of putting the rest of the function inside of the "else" of your conditional; it makes the code easier to read and understand. When I'm trying to understand what a function does, I don't want to have to scan through all the code hunting for hidden returns and strange control flow. A straightforward 'if' or 'cond' makes it very clear under what circumstances each piece of code will be used.

If you think hard about why you like the "when+return" solution, I suspect that at some level, you want to take that guard and "get it out of the way" of your cognitive processes, allowing the rest of the function to be the focal point. This (I claim) is a recipe for subtle bugs.

Search your feelings; you know it to be true!

EDIT: an ant just crawled across my laptop. This is a sign that I'm speaking the truth.




回答3:


A simple way in Racket:

(define (foo x)
  (let/ec return
    (when (= x 0)
       (return 'zero))
    'not-zero))

Here ec stands for escape continuations, which are cheaper than full continuations.




回答4:


Simple:

(and (x) y)

The problem is that "when" doesn't return a value. "and" does.



来源:https://stackoverflow.com/questions/29934035/returning-from-a-function-inside-when-statement

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!