我是计划的新手。我试图使用方案找到列表的最大值和最小值。使用"循环"我得到了答案。现在我尝试以不同的方式实现同样的事情。我做了一些改变,由于某种原因,我无法找到我做错的事。
;non working version
(define (min-max list1)
(let (ls list1) (max (car list1)) (min(car list1))
(cond
((null? ls)
(list "max: " max "min: " min))
((> (car ls) max)
(let ((car ls) max))
(min-max (cdr ls)))
((< (car ls) min)
(let ((car ls) min))
(min-max (cdr ls)))
(else
(min-max (cdr ls))))))
(define list1(list 1 2 3 4 ))
(display list1)
(newline)
(min-max list1)
;working version
(define (min list1)
(let loop((ls list1) (max (car list1)) (min(car list1)))
(cond
((null? ls)
(list "max: " max "min: " min))
((> (car ls) max)
(loop (cdr ls)(car ls) min))
((< (car ls) min)
(loop (cdr ls) max (car ls) ))
(else
(loop (cdr ls) max min)))))
(define list1(list 1 2 3 4 ))
(display list1)
(newline)
(min list1)
答案 0 :(得分:1)
这不是代码审查,但我将首先从您的程序的“工作”版本开始。按原样,该过程不适用于空列表,因此您应该为此添加测试。然后,无需将列表的第一个元素重新比较为min
和max
。然后,您似乎认为loop
是关键字,因此我将名称更改为helper
。最后,我将其修改为重复性较低:
(define (min-max lst)
(if (null? lst)
'()
(let helper ((lst (cdr lst)) (min (car lst)) (max (car lst)))
(if (null? lst)
(list min max)
(let ((c (car lst)))
(helper (cdr lst)
(if (< c min) c min)
(if (> c max) c max)))))))
与
相同(define (min-max lst)
(define (helper lst min max)
(if (null? lst)
(list min max)
(let ((c (car lst)))
(helper (cdr lst)
(if (< c min) c min)
(if (> c max) c max)))))
(if (null? lst)
'()
(helper (cdr lst) (car lst) (car lst))))
测试:
> (min-max '(1 2 3 4))
'(1 4)
> (min-max '(1 8 2 3 4))
'(1 8)
> (min-max '())
'()
您的第一个程序不起作用,因为在每次递归调用时您都会重新初始化min
和max
。此外,由于没有对空列表进行测试,因此您不可避免地会获取空列表的car
,这在Scheme中是不允许的。最后,看起来您想要在递归调用之外更改min
和max
的值,这意味着您必须使用set!
。这是一个有效的版本:
(define (min-max lst)
(if (null? lst)
'()
(let ((min (car lst)) (max (car lst)))
(define (helper lst)
(if (null? lst)
(list min max)
(let ((c (car lst)))
(when (< c min) (set! min c))
(when (> c max) (set! max c))
(helper (cdr lst)))))
(helper lst))))
这会产生相同的结果,但是与set!
的递归调用相比,您可以看到helper
代码看起来更不优雅。