简体   繁体   中英

How do I stop recursion and return something in racket?

NOTE: I would like to do this without rackets built in exceptions if possible.

I have many functions which call other functions and may recursively make a call back to the original function. Under certain conditions along the way I want to stop any further recursive steps, and no longer call any other functions and simply return some value/string (the stack can be ignored if the condition is met).. here is a contrived example that hopefully will show what I'm trying to accomplish:

(define (add expr0 expr1)
(cond
 [(list? expr0) (add (cadr expr0) (cadr (cdr expr0)))]
 [(list? expr1) (add (cadr expr1) (cadr (cdr expr1)))]
 [else (if (or (equal? expr0 '0) (equal? expr1 '0))
         '(Adding Zero)
         (+ expr0 expr1))]
))

If this were my function and I called it with (add (add 2 0) 3), Then the goal would be to simply return the entire string '(Adding Zero) ANYTIME that a zero is one of the expressions, instead of making the recursive call to (add '(Adding Zero) 3)

Is there a way to essentially "break" out of recursion? My problem is that if i'm already deep inside then it will eventually try to evaluate '(Adding Zero) which it doesn't know how to do and I feel like I should be able to do this without making an explicit check to each expr..

Any guidance would be great.

In your specific case, there's no need to "escape" from normal processing. Simply having '(Adding Zero) in tail position will cause your add function to return (Adding Zero) .

To create a situation where you might need to escape, you need something a little more complicated:

(define (recursive-find/collect collect? tree (result null))
    (cond ((null? tree) (reverse result))
          ((collect? tree) (reverse (cons tree result)))
          ((not (pair? tree)) (reverse result))
          (else
            (let ((hd (car tree))
                  (tl (cdr tree)))
              (cond ((collect? hd)
                     (recursive-find/collect collect? tl (cons hd result)))
                    ((pair? hd)
                     (recursive-find/collect collect? tl
                               (append (reverse (recursive-find/collect collect? hd)) result)))
                    (else (recursive-find/collect collect? tl result)))))))

Suppose you wanted to abort processing and just return 'Hahaha! if any node in the tree had the value 'Joker . Just evaluating 'Hahaha! in tail position wouldn't be enough because recursive-find/collect isn't always used in tail position.

Scheme provides continuations for this purpose. The easiest way to do it in my particular example would be to use the continuation from the predicate function, like this:

(call/cc
  (lambda (continuation)
    (recursive-find/collect
        (lambda (node)
            (cond ((eq? node 'Joker)
                   (continuation 'Hahaha!)) ;; Processing ends here
                   ;; Otherwise find all the symbols
                   ;; in the tree
                  (else (symbol? node))))
        '(Just 1 arbitrary (tree (stucture) ((((that "has" a Joker in it)))))))))

A continuation represents "the rest of the computation" that is going to happen after the call/cc block finishes. In this case, it just gives you a way to escape from the call/cc block from anywhere in the stack.

But continuations also have other strange properties, such as allowing you to jump back to whatever block of code this call/cc appears in even after execution has left this part of the program. For example:

(define-values a b (call/cc
                     (lambda (cc)
                        (values 1 cc))))
 (cc 'one 'see-see)

In this case, calling cc jumps back to the define-values form and redefines a and b to one and see-see , respectively.

Racket also has "escape continuations" ( call/ec or let/ec ) which can escape from their form, but can't jump back into it. In exchange for this limitation you get better performance.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM