簡體   English   中英

嘗試在球拍中編寫遞歸函數

[英]Trying to write a recursion function in racket

我正在嘗試編寫一個常規遞歸函數和一個尾遞歸函數,該函數需要四個參數並計算從qr xax^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平方加b中從x到r的x的sigma

顯然,問題尚未完全解決。 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))

它使用高級運算符mapfoldl ,今天所有很酷的語言都認為這是貓的叫聲。 也許是因為它使我們可以編寫(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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM