Recursion 如果在列表中找不到号码,如何返回false

Recursion 如果在列表中找不到号码,如何返回false,recursion,functional-programming,scheme,lisp,racket,Recursion,Functional Programming,Scheme,Lisp,Racket,因此,我试图解决这个硬件问题:编写一个函数,它包含两个参数,一个列表和一个数字,该函数返回列表中最左边的数字的索引。例如: 如果”(1234)和num=3,则返回2 如果'(3 2 3 4)和num=3,则返回0 我能做到这一点,但如果找不到号码怎么办?如果在列表中找不到num时要返回false,该怎么办?我该怎么做 请记住,我试图用正确的递归,而不是尾部递归 这是我的密码 (define (first_elt_occ lst num) (cond ((null? l

因此,我试图解决这个硬件问题:编写一个函数,它包含两个参数,一个列表和一个数字,该函数返回列表中最左边的数字的索引。例如:

  • 如果
    ”(1234)
    num=3
    ,则返回
    2

  • 如果
    '(3 2 3 4)
    num=3
    ,则返回
    0

我能做到这一点,但如果找不到号码怎么办?如果在列表中找不到
num
时要返回false,该怎么办?我该怎么做

请记住,我试图用正确的递归,而不是尾部递归

这是我的密码

(define (first_elt_occ lst num)
   (cond
       ((null? lst) #f)
       ((eq? (car lst) num) 0)
       (else
          (+ 1 (first_elt_occ (cdr lst) num)))))

(first_elt_occ '(1 2 3 3 4) 3) ;2
(first_elt_occ '(3 2 3 3 4) 3) ;0
(first_elt_occ '(1 2 5 4 3) 3) ;4
(first_elt_occ '(1 2 5 4 3) 6) ;Error 
     ;(makes sense because you can't add boolean expression)
我的另一个问题是,如果我被要求返回列表中最右边出现的数字的索引(正确的递归),我将如何处理这个问题。例如:
”(3 4 5 4 3 7)
num=3
返回
4


谢谢大家!

正如评论中所建议的,如果我们使用尾部递归来实现过程,这将更容易——顺便问一下,尾部递归是“正确的递归”,你怎么会不这么认为

通过定义一个名为
loop
的帮助程序,并将累积结果传递给一个参数,我们可以返回
#f
或元素的索引:

(define (first_elt_occ lst num)
  (let loop ((lst lst) (acc 0))
    (cond
      ((null? lst) #f)
      ((equal? (car lst) num) acc)
      (else (loop (cdr lst) (add1 acc))))))
如果,对于某些奇怪的需求,您不能在解决方案中使用尾部递归,则可以重写原始解决方案,以说明答案为
#f
时的情况-但这并没有那么优雅或高效:

(define (first_elt_occ lst num)
  (cond
    ((null? lst) #f)
    ((equal? (car lst) num) 0)
    (else
     (let ((result (first_elt_occ (cdr lst) num)))
       (if (not result) #f (add1 result))))))
无论哪种方式,它都能按预期工作:

(first_elt_occ '(1 2 3 3 4) 3) ; 2
(first_elt_occ '(3 2 3 3 4) 3) ; 0
(first_elt_occ '(1 2 5 4 3) 3) ; 4
(first_elt_occ '(1 2 5 4 3) 6) ; #f
> (first_elt_occ '(1 2 3 3 4) 3)
2
> (first_elt_occ '(3 2 3 3 4) 3)
0
> (first_elt_occ '(3 2 3 3 4) 5)
#f

不清楚您为什么反对尾部递归。你说的是“适当的递归”,这不是任何人使用的技术术语,但我假设你指的是非尾部递归:用SICP术语来说,是递归过程,而不是迭代过程。请放心,尾部递归是非常合适的,并且通常比非尾部递归更好,前提是不必进行其他权衡来启用尾部递归


正如奥斯卡·洛佩斯所说,用尾部递归确实更容易解决这个问题。但如果你坚持,当然可以用艰难的方式解决它。您必须避免盲目地将1添加到结果中:相反,检查它,如果它是一个数字,则将1添加到结果中,如果它为false,则返回不变的结果。例如,请参阅
number?
谓词。

我不建议实际采用这种方法,因为正常的尾部递归实现效率更高、更简单、更容易理解,但在故障情况下,您可以使用continuation来短路解除调用堆栈:

(define (first_elt_occ lst num)
  (call/cc
   (lambda (return)
     (letrec ((loop (lambda (lst)
                      (cond
                       ((null? lst) (return #f))
                       ((= (car lst) num) 0)
                       (else (+ 1 (loop (cdr lst))))))))
        (loop lst)))))
第一次出现的基本查找是

但这不会返回索引。如何添加它

(define (first_elt_occ lst num)
   (and (not (null? lst))
        (or (and (equal (car lst) num) 0)
            (+ 1 (first_elt_occ (cdr lst) num)))))
它有用吗?如果元素不在那里就不会!那会导致一个错误。如何解决这个问题?更改
+
,就是这样

(define (first_elt_occ lst num)
  (let ((+ (lambda (a b) (if b (+ a b) b))))
    (and (not (null? lst))
         (or (and (= (car lst) num) 0)
             (+ 1 (first_elt_occ (cdr lst) num))))))
现在,它如预期的那样工作:

(first_elt_occ '(1 2 3 3 4) 3) ; 2
(first_elt_occ '(3 2 3 3 4) 3) ; 0
(first_elt_occ '(1 2 5 4 3) 3) ; 4
(first_elt_occ '(1 2 5 4 3) 6) ; #f
> (first_elt_occ '(1 2 3 3 4) 3)
2
> (first_elt_occ '(3 2 3 3 4) 3)
0
> (first_elt_occ '(3 2 3 3 4) 5)
#f
为了得到你想要的第二个函数,我们将它重新构造一点,变成

(define (first_elt_occ lst num)
  (let ((+ (lambda (a b) ...... )))
    (and (not (null? lst))
         (+ (and (= (car lst) num) 0)
            (first_elt_occ (cdr lst) num)))))

现在,新的
+
应该是什么?你能把这个做完吗?这很简单

尾部递归非常简单(而且效率更高)……要求很高!:)您在同一帖子中有两个不同的问题,让我们在这里解决第一个问题,并在您找到第一个问题的满意答案后发布第二个问题。谢谢。我的教授希望我们使用尾部递归和“适当递归”来实现这个问题——堆栈的增长和收缩。我已经知道如何在尾部递归中实现它。谢谢。我的教授希望我们使用尾部递归和“适当递归”来实现这个问题——堆栈的增长和收缩。我已经知道如何在尾部递归中实现它。