Recursion 复制长度函数的有效方法

Recursion 复制长度函数的有效方法,recursion,scheme,lisp,racket,Recursion,Scheme,Lisp,Racket,我正在复制racket的length函数,使用car&cdr比较两个列表的长度,并返回两个列表中较短的一个 简单地说,长度函数是: (define length (lambda (list) (if (null? list) 0 (+ 1 (length (cdr list)))))) 当用于比较两个列表时 (define short (lambda (list1 list2) (if (<= (length list1) (leng

我正在复制racket的length函数,使用car&cdr比较两个列表的长度,并返回两个列表中较短的一个

简单地说,长度函数是:

(define length
 (lambda (list)
    (if (null? list)
        0
        (+ 1 (length (cdr list))))))
当用于比较两个列表时

(define short
  (lambda (list1 list2)
    (if (<= (length list1) (length list2))
        list1
        list2)))

> (short '(a b c) '(1 2 3 4 5 6 7))

我建议这样开始:

(define (shorter list-1 list-2) (shorter-loop list-1 list-2 list-1 list-2))
然后


其中,helper函数shorter循环同时向下递归list-1和list-2。如果list-1变为null,则返回结果-1;如果list-2变为null,则返回结果-2。

您的
更短?
过程已经尽可能地高效了-
特殊形式短路,并且在任何计算表达式的值为
true
(对于
特殊表单)或
false
(对于
特殊表单)。因此,一旦其中一个列表达到
null
,递归就会停止。您的
shorter?
实现相当于,并且与此一样高效:

(define shorter?
  (lambda (list1 list2)
    (cond ((null? list2) #f)
          ((null? list1) #t)
          (else (shorter? (cdr list1) (cdr list2))))))
如果您想要更紧凑的解决方案,可以使用命名的
let
(如另一个答案中所示)或内部帮助程序将两个过程放在一个过程中,这两个过程都是等效的。我将演示后面的方法:

(define (shorter lst1 lst2)
  (define (shorter-list list1 list2)
    (cond ((null? list2) lst2)
          ((null? list1) lst1)
          (else (shorter-list (cdr list1) (cdr list2)))))
  (shorter-list lst1 lst2))

“named let”方法提供易于理解的代码。注释提供了解释:

(define (shorter l1 l2)
  (let loop ((al l2)         ; start with both full lists
             (bl l2))
    (cond
      [(empty? al) l1]       ; if al finishes, return l1 and end; 
      [(empty? bl) l2]       ; if bl finishes, return l2 and end;
      [else
       (loop (cdr al) (cdr bl))] ; else loop again with cdr of lists;
    )))

此功能将在Shorrer列表完成时结束,并且不会不必要地继续到较长列表的末尾。

这并不能回答问题
(define (shorter lst1 lst2)
  (define (shorter-list list1 list2)
    (cond ((null? list2) lst2)
          ((null? list1) lst1)
          (else (shorter-list (cdr list1) (cdr list2)))))
  (shorter-list lst1 lst2))
(define (shorter l1 l2)
  (let loop ((al l2)         ; start with both full lists
             (bl l2))
    (cond
      [(empty? al) l1]       ; if al finishes, return l1 and end; 
      [(empty? bl) l2]       ; if bl finishes, return l2 and end;
      [else
       (loop (cdr al) (cdr bl))] ; else loop again with cdr of lists;
    )))