用于返回平方数列表之和的 Racket 递归函数

Racket recursive function for returning the sum of a list of squared numbers

我是 Racket 的新手,我正在尝试编写一个递归函数,它接受一个数字 n 和 returns 第一个 n 整数的平方和。例如,(this-function 3) returns 14 因为 14 是 9 + 4 + 1 + 0。

我尝试创建两个单独的函数,一个对每个数字求平方,returns 一个平方数列表,第二个对列表求和。每个数字平方的函数是:

(define (squared my-list)
  (cond [(empty? my-list) empty]
        [(zero? my-list) 0] 
        [else (cons (expt  my-list 2)
                    (cons (squared   (sub1 my-list)) empty))]))

如果我 运行 (squared 3) returns (cons 9 (cons (cons 4 (cons (cons 1 (cons 0 empty)) empty)) empty)).

当我运行第二个函数(求和函数)时:

(define (sum numbers)
  (cond
    [(empty? numbers) 0]
    [else (+ (first numbers) (sum (rest numbers)))]))

和 运行 (sum (squared 3)) 我收到一条错误消息,因为 (squared 3) returns 列表中有一个额外的 "cons"。

我该如何解决这个问题?

最直接的解决方案是使用封闭形式:

(define (sum-of-squares n)
  (* 1/6 n (+ n 1) (+ n n 1)))

来源:WolframAlpha

您在 squared 中的逻辑有点不对劲。我会逐条解释这些问题。

[(empty? my-list) empty]

这没有任何意义,因为 my-list 永远不会成为列表。事实上,my-list 命名不当。 squared 接受的参数是一个 数字 ,而不是一个列表。这个条款可以完全删除。

[(zero? my-list) 0]

这是 实际 终止案例应该是什么,但它不应该 return 0。请记住,squared 必须 return 一个 list,而不是一个数字。 这个案例应该return empty.

[else (cons (expt my-list 2)
            (cons (squared (sub1 my-list)) empty))]))

最后,这个条款太复杂了。您的想法是正确的 — cons 将新号码添加到列表的其余部分 — 但您的想法太多了。请记住,(squared (sub1 my-list)) 的结果本身就是一个列表,而 cons 的第二个参数是列表的其余部分。你不需要额外的缺点——你可以完全消除它。

结合这些变化,你得到这个,它做你想要的:

(define (squared my-list)
  (if (zero? my-list) empty
      (cons (expt my-list 2)
            (squared (sub1 my-list)))))

(我还用 if 替换了 cond,因为不再需要 cond。)


就是说,这段代码不是很 Racket-y。您有一个将函数分解为两个函数的好主意 — 在函数式编程中,函数实际上应该只做 一个 事情 — 但您可以进一步分解它!具体来说,你可以利用 Racket 的内置高阶函数来使这类事情变得非常容易。

您可以通过适当组合 map and range 来替换整个 squared 功能。例如,下面创建一个从 0–3 的正方形列表。

(map (curryr expt 2) (range 4))

(您需要调用 (<a href="http://docs.racket-lang.org/reference/pairs.html?q=range#%28def._%28%28lib._racket%2Flist..rkt%29._range%29%29" rel="nofollow">range</a> 4) because the list generated by range 从 0 到 n-1。)

接下来,您可以使用 apply 轻松对列表求和。总结上面的列表,你会做这样的事情:

(apply + (map (curryr expt 2) (range 4)))

这为您提供了 14 的适当结果。显然,为了清楚起见,您可以将它封装在它自己的函数中,但是一旦您了解了 Racket 的函数结构,上面的代码在做什么就清楚多了。

(但是,我不确定您是否可以使用这些,因为您的问题看起来很像家庭作业。只是为了将来的参考和完整性而注明。)

不需要一个提供正方形列表的函数和一个汇总列表的函数。 这将达到目的,并且根据需要递归。

(define (my-sq n)
(cond [(zero? n) 0]
      [else
       (+ (* n n) (my-sq (- n 1)))]))

(my-sq 3) -> 14