如何从 Scheme 中的递归调用中正确 return 值?

How to properly return value from a recursive call in Scheme?

我的目标是为 plus-minus 方法提供一个列表,以便它可以遍历所有可能的情况,在这种情况下,如果任何给定数量的元素都为负数,然后从剩余正数的总和中减去numbers 有可能在原始列表中找到或找不到该数字。

例如:如果我们向 plus-minus 提供 (3 1 2) 的列表,那么 plus-minus 应该 return #t 一旦达到 (3 1 -2 ), 因为 4 - 2 = 2 并且 2 在 (3 1 2) 的原始列表中。

我有一个独立于plus-minusref-check的方法,用于判断目标号码是否在列表中。因此,在提供的示例中,它的工作是确定 2 是否存在于 (3 1 2) 的原始列表中。因为它确实存在于原始列表中,所以 ref-check 是 return 1 for #t.

我目前的问题是 ref-check 确实 return #t 返回到 plus-minus,但无论如何该方法似乎仍在继续。

我觉得这个问题似乎有一个简单的解决方案。

工作代码:

;returns true if the element is in the list otherwise false
(define ref-check(lambda (list element)
            (cond
             ((null? list) 0)
             ((= element (car list)) 1)
             (else (ref-check (cdr list) element)))))


;main calculation
(define plus-minus(lambda (L sum1 sum2)
                    (cond
                      ((null? L) #f)
                      ((= (ref-check L (- sum1 sum2)) 1) #t)
                      (else (plus-minus (cdr L) (+ sum1 (car L)) sum2)
                            (plus-minus (cdr L) sum1 (+ sum2 (car L)))))))

示例输入:(plus-minus '(7 5 1 2) 0 0) 结果示例:#t

编辑:正确和清晰

让我们开始回答问题:

My issue currently is that ref-check does return #t[1] back to plus-minus, but the method seems to continue regardless.

如果 ref-check returns 1 到您的调用函数,进一步的递归调用 不会 从当前调用堆栈进一步向下。所以,在 ref-check returned 之后,调用 plus-minus also returns.

但是它return调用它的函数,可能是"you"(即顶层),但 更有可能 将是 "itself"。一个例子可能会更好地说明这一点:

让我们调用 (plus-minus '(3 1 2) 0 0):这将登陆 condelse 分支,首先调用 (plus-minus '(1 2) 3 0)。这也将落在 else 分支中,因此首先调用 (plus-minus '(2) 5 0)(最终将 return #f,因此我们忽略它)然后 (plus-minus '(2) 3 1) .在 thatplus-minus 的调用中,由于 [=11],它将到达 returns #tcond 的分支=](3-1 == 2(1 2) 的一部分)。函数 returns 到它的调用者,实际上是 "in the else branch" 第一次调用 plus-minus。在那里,您丢弃 returned 值,并无条件地调用 (plus-minus '(1 2) 0 3),这将进一步调用 ref-checkplus-minus

直观地显示部分调用堆栈:

(plus-minus '(3 1 2) 0 0)
  ;; In else
  (plus-minus '(1 2) 3 0)
     ;; In else
     (plus-minus '(2) 5 0)
        ;; Details discarded, returns #f
        ;; <== #f
     ;; Discard #f from above, and call
     (plus-minus '(2) 3 1)
       ;; ref-check returned 1, so return #t
       ;; <== #t
     ;; <== #t
  ;; Still in the else, got #t, discard, then
  (plus-minus '(1 2) 0 3)
     ;; ...

要摆脱这种情况,您需要进行第二次递归调用 如果第一个还没有 return #t。这可以通过将两个调用包装在 (or ...).

中轻松实现

[..] how I ensure ref-check always receives the original list,

每次调用 plus-minus.

时将原始列表作为附加参数向下传递

(3 1 2 400) should always return #f

按照你现在的逻辑,那不会发生。由于您调用 ref-check 也使用部分计算的 sum1sum2 (即不是列表中的所有元素 "decided" 但无论它们是否为负数)以上将产生 #t.

要获得所需的行为,您需要在列表的所有元素都添加到 sum1 或 [=45] 时仅调用 ref-check =],因此当没有更多元素要处理时,即当列表为空时。

现在,一些评论:

  • 不要用01来表示真实性,在Scheme中你应该用#f来表示false和其他任何东西(#t如果你不能有意义地 return 任何东西)对于 true.
  • 缩进和间距:你真的应该遵守这里既定的标准。通常情况下,您的编辑器应该会处理这个问题。
  • 别说"methods"。它被称为函数

我没有提供 "final working" 代码让您自己实施上述修复。