2016-07-20 69 views
2

在方案中,您可以定義返回lambda表達式並使用它們來定義新函數的函數。例如,你可以這樣寫代碼函數求值爲lambda不能用於定義範圍內的新函數

(define (pow-iter base exp r) 
    (if (= exp 1) 
     r 
     (pow-iter base (- exp 1) (* base r)))) 

(define (pow exp) 
    (lambda (base) 
    (pow-iter base exp base))) 

(define cubic (pow 3)) 

(cubic 2) 

我們這裏有一個功能pow這需要指數作爲參數,計算結果爲求值爲定基本的n次方lambda函數。

但是,如果我們把像這樣一個範圍內:

(define (do-cubic x) 
    (define (pow-iter base exp r) 
    (if (= exp 1) 
     r 
     (pow-iter base (- exp 1) (* base r)))) 

    (define (pow exp) 
    (lambda (base) 
     (pow-iter base exp base))) 

    (define cubic (pow 3)) 

    (cubic x)) 

(do-cubic 2) 

我得到一個錯誤

pow: undefined; cannot use before initialization

爲什麼會出現這種錯誤發生,有沒有什麼辦法解決它在不改變程序的邏輯?

+0

球拍的詳細信息我噸工作。 – Renzo

+0

@Renzo你的意思是它在'#!racket'中有效。在'#!r5rs'中,即使在RacketVM下,它也會失敗。他們是不同的語言。 – Sylwester

回答

3

這個節目引發了同樣的錯誤:

#lang r5rs 
(let() 
    (define (foo x) (lambda (y) (+ 42 x))) 
    (define bar (foo 1)) 
    (bar 2)) 

Output: 
    foo: undefined; 
    cannot use before initialization 

你得到一個錯誤的原因是「內部定義」被改寫成letrec表達所有綁定都在影響,而被計算它們的初始值,從而允許相互遞歸的定義。

(letrec ((foo (lambda (x) (lambda (y) (+ 42 x)))) 
     (bar (foo 1))) 
(bar 2)) 

在R5RS初始化表達式在一個未指定順序進行評估。這意味着在上面的第一個片段中,(define bar (foo 1))可能在(define (foo x) ...)之前被評估。換句話說,在foo已被初始化之前需要foo的值。

在球拍(#lang racket)內部定義使用letrec* -semantics(即初始化表達式在它們出現在碼的順序進行評估,因此,該程序在沒有錯誤。

還要注意,在letrec對應#lang racket什麼letrec*確實在「R5RS」 -implementations。

有關letrec VS letrec*看到介紹的http://www.cs.indiana.edu/~dyb/pubs/letrec-reloaded.pdf

相關問題