簡體   English   中英

球拍:識別尾遞歸?

[英]Racket: Identifying tail recursion?

我在球拍中寫了兩個不同的函數來確定數字列表是否在升序:

(define (ascending list)
  (if (<= (length list) 1)
      #t
      (and (< (car list) (car (cdr list))) (ascending (cdr list)))))

(define (ascending-tail list)
  (ascending-tail-helper #t list))

(define (ascending-tail-helper prevBool rest)
  (if (<= (length rest) 1)
      prevBool
      (ascending-tail-helper (and prevBool (< (car rest) (car (cdr rest)))) (cdr rest))))

我最難確定第一次提升是否是尾遞歸,所以我用我認為的尾遞歸重寫了它。

我回顧性地認為第一個不是尾遞歸的原因是我相信在每個遞歸級別,函數將等待“and”語句中的第二個參數返回,然后才能評估布爾表達式。 相反,對於升序尾助手,我能夠在進行遞歸調用之前評估小於表達式。

這是正確的,還是讓自己比以前更加困惑?

DrRacket可以幫助您確定呼叫是否處於尾部位置。 單擊“語法檢查”按鈕。 然后將鼠標指針移動到相關表達式的左括號。 在你的例子中,我得到了這個:

在此輸入圖像描述

紫色箭頭表示表達式處於尾部位置。

從手冊:

尾調用:通過從尾表達式到其周圍表達式繪制淺紫色箭頭來注釋(語法上)相對於其封閉上下文在尾部位置的任何子表達式。

你是正確的,在第一個版本的遞歸調用返回and ,而在第二個版本的遞歸調用是一個尾調用。

但是, and是一個宏,並且通常使用if擴展

(define (ascending list)
  (if (<= (length list) 1)
      #t
      (if (< (car list) (car (cdr list)))
          (ascending (cdr list))
           #f)))

這是尾遞歸。

函數處於尾部位置的要求之一是它的返回值可用作父函數的返回值而無需修改或檢查。 也就是說,在評估尾部位置語句之后,父函數應該能夠立即返回。

在第一次出現時,您的第一個功能,檢查升序的返回值。 似乎不會返回提升的價值,而是從它中獲得的價值。 然而 ,根據該規范R5RS的相關部分,在一個最終表達式語句在尾部位置。 (當我清醒的時候,我知道這一點)

所以你錯了。

http://www.schemers.org/Documents/Standards/R5RS/HTML/r5rs-ZH-6.html#%_sec_3.5

(注意:編輯以糾正我最初倉促的答案)。

關於尾部位置的 Racket 文檔說明了檢查尾部位置和不匹配的位置是特定形式的文檔:

尾部位置規范提供了關於計算的漸近空間消耗的保證。 一般來說,尾部位置的規范與每種句法形式一致, if

Racket的文檔說(重點補充):

 (and expr ...) 

如果沒有提供exprs,則結果為#t。

如果提供了單個expr,那么它處於尾部位置 ,因此和表達式的結果是expr的結果。

否則,將評估第一個expr。 如果它產生#f,則表達式的結果為#f。 否則,結果與a和表達式相同,其中尾部位置的剩余exprs相對於原始和形式。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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