简体   繁体   English

尝试在球拍中编写递归函数

[英]Trying to write a recursion function in racket

I'm trying to write a regular recursion function and a tail-recursion function which takes four arguments and evaluates the sum of ax^2 + b for x from q to r . 我正在尝试编写一个常规递归函数和一个尾递归函数,该函数需要四个参数并计算从qr xax^2 + b的总和。

This is what I have so far and it is not working, can I get some information on what is wrong with my code? 到目前为止,这是我所拥有的,并且无法正常工作,我能否获得有关我的代码有什么问题的信息?

(define (sumof a b q r)

  (define (sum) 
    (+ (* (expt q 2) a) b))

  (if ( = q r)
      0
      (+ (+ q 1) (sum))))

Here's the correct way to call the recursion: 这是调用递归的正确方法:

(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))))

You should pass along the parameter that changes at each iteration, that's cleaner than capturing it from the defining environment. 您应该传递每次迭代都会更改的参数,这比从定义环境捕获参数更干净。 And notice how the sumof function must call itself for iterating. 并注意sumof函数必须如何调用自身进行迭代。 As a side note, your function is not tail-recursive. 另外,您的函数不是尾递归的。 A proper tail recursion would look like this: 正确的尾递归应如下所示:

(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)))))

It's not surprising that it is difficult to write code. 编写代码很困难也就不足为奇了。 Though recursion is useful, this is about the worst way to introduce it because using recursion for this problem goes against any inclination toward sound software engineering practice. 尽管递归很有用,但这是引入递归的最糟糕的方法,因为对这个问题使用递归与合理的软件工程实践毫无二致。

Mathematic Specification 数学规格

Looking at the basic equation: 看基本方程式:

在x平方加b中从x到r的x的sigma

It's clear that the problem isn't fully specified. 显然,问题尚未完全解决。 Is it x < r or x <= r ? x < r还是x <= r At least writing a specification made the assumption that might lead to an off-by-one error explicit. 至少编写一个规范做出了一个假设,该假设可能明确地导致一个偏离一个的错误。

Implementation 实作

I meant what I said about this problem being detrimental to sound software engineering. 我的意思是我对这个问题说的话不利于完善的软件工程。 There are places for recursion. 有递归的地方。 Those places are exactly where recursion makes the code clearer and easier to understand. 这些地方正是递归使代码更清晰和易于理解的地方。 This is not one of those cases. 不是其中一种情况。 This is a case where the specification is iterative and writing the implementation recursively adds complexity and opacity. 在这种情况下,规范是迭代的,并且递归编写实现会增加复杂性和不透明性。

If we stay close to the specification: 如果我们保持接近规格:

#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))

This uses the high level operators map and foldl that all today's cool languages think are the cat's meow. 它使用高级运算符mapfoldl ,今天所有很酷的语言都认为这是猫的叫声。 Perhaps because it lets us write things like (sigma q<=x<=r ax^2+b) . 也许是因为它使我们可以编写(sigma q<=x<=r ax^2+b)

But it's HomeWork 但这是家庭作业

What makes this so bad is the Computer Science of tail-recursion is founded on the isomorphism between a particular class of recursive descriptions of algorithms and iterative descriptions. 令其如此糟糕的是,尾递归计算机科学是建立在特定类型的算法递归描述与迭代描述之间的同构之上的。 The idea of a programming language is to make reading and writing our programs easier. 编程语言的思想是使阅读和编写我们的程序更加容易。

Though one would never guess it based on the assignment #lang racket includes a construct exactly for the purpose of explicitly expressing the isomorphism of tail-recursion and writing tail-recursive algorithms more clearly. 尽管永远不会根据分配猜测它,但#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))

The (let loop... syntax makes it clear that the tail-recursive call is really a loop. (let loop...语法清楚地表明,尾递归调用实际上是一个循环。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM