简体   繁体   中英

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 .

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. 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 ? 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. Perhaps because it lets us write things like (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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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