Scheme/Racket - 计算列表中的所有正值
Scheme/Racket - Count all positive vals in a list
我对 Scheme/Racket 没有太多经验,但我正在尝试制作一个函数来计算列表中有多少个正值。到目前为止我有这个:
(define num_pos 0)
(define num_neg 0)
(define (numpos lst)
(cond
((null? lst) 0)
((>= (car lst) 0) (+ num_pos 1) (numpos (cdr lst)))
(else (+ num_neg 1) (numpos (cdr lst)))
)
)
但是当我在 DrRacket 中 运行 并对其进行测试时,lst 始终为空,因此如果我调用 (numpos '(1 -1 2)) 它 returns 0 by the null检查,但如果我删除空检查,它会在 (car lst) 上崩溃,说它需要一对但得到 '()。我在这上面花了一点点运气。有任何想法吗?
(+ num_pos 1)
不会改变 num_pos
的值。尝试将其替换为 (set! num_pos (+ num_pos 1))
并对 num_neg
.
执行相同的操作
调用(numpos '(1 -1 2))
后,num_pos
的值变为2。
编辑:
我完全同意 Óscar 的评论,他已经添加了更好的答案。这是一个带有额外 num_neg
支持的替代示例:
(define (numpos lst num_pos num_neg)
(cond
((null? lst)
(list num_pos num_neg))
((>= (car lst) 0)
(numpos (cdr lst) (+ num_pos 1) num_neg))
(else
(numpos (cdr lst) num_pos (+ num_neg 1)))))
如果你调用 (numpos '(1 -1 2) 0 0)
那么它 returns 一个包含正值和负值数量的列表,如 (2 1)
.
请注意,新版本需要额外的 2 个参数,每个参数都必须为 0。这些参数在原始代码中的作用类似于 num_pos
和 num_neg
。这是 tail recursive.
使用尾递归,您可以轻松消除副作用(全局变量访问)。
如果您不喜欢那些额外的参数,您可以使用内部 define
重写,如下所示:
(define (numpos lst)
(define (iter lst num_pos num_neg)
(cond
((null? lst)
(list num_pos num_neg))
((>= (car lst) 0)
(iter (cdr lst) (+ num_pos 1) num_neg))
(else
(iter (cdr lst) num_pos (+ num_neg 1)))))
(iter lst 0 0))
在 Scheme 中,我们尝试使用 functional programming 范式编写过程。在你的例子中,定义一个计数器 outside 过程不是一个好主意,要改变它的值你需要 mutate 它内部使用set!
指令,我们应该避免这样做。
通常的解决方案(如果我们要解决这个 "by hand")是递归遍历列表并在每次递归调用时递增值,注意我们甚至不需要递增变量在程序内部,像这样:
(define (numpos lst)
(cond
((null? lst) 0)
((>= (car lst) 0) (+ 1 (numpos (cdr lst))))
(else (numpos (cdr lst)))))
了解其工作原理的关键在于:
(+ 1 (numpos (cdr lst)))
我们将递归的结果加一,对每个正数继续这样做,直到我们到达列表的末尾,并在末尾添加一个零。
在你的代码中,你写了这个:(+ num_pos 1)
,但是那个表达式并没有改变 num_pos
的值,它只是加一零,但永远不会存储加法的结果!
现在我们可以给变量定义合适的值了,我们只需要用程序计算num_pos
,num_neg
的值就很容易推导出来了:
(define num_pos (numpos lst))
(define num_neg (- (length lst) num_pos))
有很多方法可以解决这个问题。熟悉递归过程后,您会发现有大量内置过程可以让您快速找到常见问题的解决方案。事实上,回答问题的惯用方法是使用 count
:
(define (numpos lst)
(count (lambda (n) (>= n 0))
lst))
我对 Scheme/Racket 没有太多经验,但我正在尝试制作一个函数来计算列表中有多少个正值。到目前为止我有这个:
(define num_pos 0)
(define num_neg 0)
(define (numpos lst)
(cond
((null? lst) 0)
((>= (car lst) 0) (+ num_pos 1) (numpos (cdr lst)))
(else (+ num_neg 1) (numpos (cdr lst)))
)
)
但是当我在 DrRacket 中 运行 并对其进行测试时,lst 始终为空,因此如果我调用 (numpos '(1 -1 2)) 它 returns 0 by the null检查,但如果我删除空检查,它会在 (car lst) 上崩溃,说它需要一对但得到 '()。我在这上面花了一点点运气。有任何想法吗?
(+ num_pos 1)
不会改变 num_pos
的值。尝试将其替换为 (set! num_pos (+ num_pos 1))
并对 num_neg
.
调用(numpos '(1 -1 2))
后,num_pos
的值变为2。
编辑:
我完全同意 Óscar 的评论,他已经添加了更好的答案。这是一个带有额外 num_neg
支持的替代示例:
(define (numpos lst num_pos num_neg)
(cond
((null? lst)
(list num_pos num_neg))
((>= (car lst) 0)
(numpos (cdr lst) (+ num_pos 1) num_neg))
(else
(numpos (cdr lst) num_pos (+ num_neg 1)))))
如果你调用 (numpos '(1 -1 2) 0 0)
那么它 returns 一个包含正值和负值数量的列表,如 (2 1)
.
请注意,新版本需要额外的 2 个参数,每个参数都必须为 0。这些参数在原始代码中的作用类似于 num_pos
和 num_neg
。这是 tail recursive.
使用尾递归,您可以轻松消除副作用(全局变量访问)。
如果您不喜欢那些额外的参数,您可以使用内部 define
重写,如下所示:
(define (numpos lst)
(define (iter lst num_pos num_neg)
(cond
((null? lst)
(list num_pos num_neg))
((>= (car lst) 0)
(iter (cdr lst) (+ num_pos 1) num_neg))
(else
(iter (cdr lst) num_pos (+ num_neg 1)))))
(iter lst 0 0))
在 Scheme 中,我们尝试使用 functional programming 范式编写过程。在你的例子中,定义一个计数器 outside 过程不是一个好主意,要改变它的值你需要 mutate 它内部使用set!
指令,我们应该避免这样做。
通常的解决方案(如果我们要解决这个 "by hand")是递归遍历列表并在每次递归调用时递增值,注意我们甚至不需要递增变量在程序内部,像这样:
(define (numpos lst)
(cond
((null? lst) 0)
((>= (car lst) 0) (+ 1 (numpos (cdr lst))))
(else (numpos (cdr lst)))))
了解其工作原理的关键在于:
(+ 1 (numpos (cdr lst)))
我们将递归的结果加一,对每个正数继续这样做,直到我们到达列表的末尾,并在末尾添加一个零。
在你的代码中,你写了这个:(+ num_pos 1)
,但是那个表达式并没有改变 num_pos
的值,它只是加一零,但永远不会存储加法的结果!
现在我们可以给变量定义合适的值了,我们只需要用程序计算num_pos
,num_neg
的值就很容易推导出来了:
(define num_pos (numpos lst))
(define num_neg (- (length lst) num_pos))
有很多方法可以解决这个问题。熟悉递归过程后,您会发现有大量内置过程可以让您快速找到常见问题的解决方案。事实上,回答问题的惯用方法是使用 count
:
(define (numpos lst)
(count (lambda (n) (>= n 0))
lst))