[英]Trying to write a recursion function in racket
我正在尝试编写一个常规递归函数和一个尾递归函数,该函数需要四个参数并计算从q
到r
x
的ax^2 + b
的总和。
到目前为止,这是我所拥有的,并且无法正常工作,我能否获得有关我的代码有什么问题的信息?
(define (sumof a b q r)
(define (sum)
(+ (* (expt q 2) a) b))
(if ( = q r)
0
(+ (+ q 1) (sum))))
这是调用递归的正确方法:
(define (sumof a b q r)
(define (sum q) (+ (* (expt q 2) a) b))
(if (= q r)
0
(+ (sum q)
(sumof a b (+ q 1) r))))
您应该传递每次迭代都会更改的参数,这比从定义环境捕获参数更干净。 并注意sumof
函数必须如何调用自身进行迭代。 另外,您的函数不是尾递归的。 正确的尾递归应如下所示:
(define (sumof a b q r)
(define (sum x) (+ (* a x x) b))
(let loop ((q q) (acc 0))
(if (= q r)
acc
(loop (+ q 1) (+ (sum q) acc)))))
编写代码很困难也就不足为奇了。 尽管递归很有用,但这是引入递归的最糟糕的方法,因为对这个问题使用递归与合理的软件工程实践毫无二致。
看基本方程式:
显然,问题尚未完全解决。 是x < r
还是x <= r
? 至少编写一个规范做出了一个假设,该假设可能明确地导致一个偏离一个的错误。
我的意思是我对这个问题说的话不利于完善的软件工程。 有递归的地方。 这些地方正是递归使代码更清晰和易于理解的地方。 这不是其中一种情况。 在这种情况下,规范是迭代的,并且递归编写实现会增加复杂性和不透明性。
如果我们保持接近规格:
#lang racket
(provide sumof)
(define/contract (sumof a b q r)
(number? number? number? number? . -> . number?)
(define/contract (sigma list-of-numbers f)
((listof number?) (number? . -> . number?) . -> . number?)
(foldl + 0 (map f list-of-numbers)))
;; range will return '() if r + 1 >= q
(define q<=x<=r (range q (add1 r)))
;; a and b are already in lexical scope
(define (ax^2+b x)
(+ (* a x x) b))
;; if the range is empty return zero
;; becuase zero is the identity of addition
(if (pair? q<=x<=r)
(sigma q<=x<=r ax^2+b)
0))
它使用高级运算符map
和foldl
,今天所有很酷的语言都认为这是猫的叫声。 也许是因为它使我们可以编写(sigma q<=x<=r ax^2+b)
。
令其如此糟糕的是,尾递归计算机科学是建立在特定类型的算法递归描述与迭代描述之间的同构之上的。 编程语言的思想是使阅读和编写我们的程序更加容易。
尽管永远不会根据分配猜测它,但#lang racket
包含一种构造,目的是明确表达尾递归的同构性,并更清楚地编写尾递归算法。
#lang racket
(provide sumof)
(define/contract (sumof a b q r)
(number? number? number? number? . -> . number?)
;; a and b are already in lexical scope
(define (ax^2+b x)
(+ (* a x x) b))
(if (< q r)
(let loop ([x-range (range q (add1 r))]
[sigma 0])
(cond
[(null? x-range) sigma]
[else (loop (rest x-range)
(+ (ax^2+b (first x-range))
sigma))]))
0))
(let loop...
语法清楚地表明,尾递归调用实际上是一个循环。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.