如何停止递归并在球拍中返回某些内容?

时间:2016-03-22 23:47:31

标签: recursion lambda functional-programming scheme racket

注意:如果可能的话,我想在没有建立异常的球拍的情况下这样做。

我有许多调用其他函数的函数,可以递归地调用回原函数。在某些条件下,我想停止任何进一步的递归步骤,不再调用任何其他函数,只是返回一些值/字符串(如果条件满足则可以忽略堆栈)..这是一个有希望的人为例子将展示我想要完成的任务:

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

如果这是我的功能,我用它来调用(添加(加2 0)3),那么目标就是简单地返回整个字符串'(添加零) ANYTIME零是其中一个表达式,而不是递归调用(添加'(添加零)3)

有没有办法基本上"打破"退出了吗?我的问题是,如果我已经深入内部,那么它最终将尝试评估它不知道该怎么做的“添加零”,我觉得我应该能做到这一点没有对每个expr进行明确检查..

任何指导都会很棒。

1 个答案:

答案 0 :(得分:0)

在您的具体情况下,无需从正常处理中“逃脱”。只需将'(Adding Zero)置于尾部位置即可使add函数返回(Adding Zero)

要创建一个您可能需要转义的情况,您需要一些东西 更复杂一点:

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

假设您想要中止处理,并且如果树中的任何节点具有值'Hahaha!,则只返回'Joker。只评估尾部位置的'Hahaha! 这是不够的,因为并不总是使用recursive-find/collect 尾部位置。

Scheme为此提供了延续。在我的特定示例中,最简单的方法是使用谓词函数的延续,如下所示:

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

延续表示在call/cc块完成后将要发生的“剩余计算”。在这种情况下,它只是为您提供了一种从堆栈中的任何位置逃离call/cc块的方法。

但是continuation还有其他奇怪的属性,比如允许你跳回到call/cc出现的任何代码块,即使在执行程序离开这部分程序之后也是如此。例如:

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

在这种情况下,调用cc会跳回define-values表单并分别将ab重新定义为onesee-see

球拍也有“逃脱延续”(call/eclet/ec),它们可以从形式中逃脱,但不能跳回到它。为了换取这种限制,您可以获得更好的性能。