2013-10-23 48 views
5

我讀的小策士和感覺困惑的下面的代碼:匿名函數在Scheme中調用自己的機制?

((lambda (len) 
    (lambda (l) 
     (cond 
     ((null? l) 0) 
     (else 
      (+ 1 (len (cdr l))))))) 
    eternity) 

(define eternity 
    (lambda (x) 
     (eternity x))) 

的代碼是確定空單,否則就永遠不會停止。

爲什麼「len」不是遞歸?

+0

「len」不是一個遞歸,因爲它是一個lambda表達式的參數。它的價值可以是任何東西。這是'永恆'。另請注意,第一個表達式不是一個定義。當評估第一個表達式時,「永恆」仍然沒有定義。 –

+0

謝謝。我明白了。 – liu

回答

5

雖然這是非常危險的文本替換應用到Lisp的形式(因爲有多個評價等的危險),在這種情況下,它可能有助於看看這個表格,看看它是如何結合在一起的:

((lambda (len) 
    (lambda (l) 
    ...)) 
eternity) 

是一個應用程序,即一個函數調用。被調用的函數帶有一個參數,稱爲len,並返回另一個函數,它接受一個參數l。被調用的函數被調用eternity。當調用完成,結果是這樣的功能:

(lambda (l) 
    (cond 
    ((null? l) 0) 
    (else (+ 1 (eternity (cdr l)))))) 

現在,這個函數將列表l,如果它是空的,返回0。否則,它計算(cdr l)(列表的其餘部分),並用該值調用eternity。當返回時,1被添加到結果中,並且這是整個函數的返回值。這個問題,當然,是eternity

(define eternity 
    (lambda (x) 
    (eternity x))) 

這也可以寫成

(define (eternity x) 
    (eternity x)) 

只是需要一個參數x,然後調用eternityx。這是一個無限循環。在上面,我寫了「什麼時候回來」,但實際上,(eternity (cdr l))從來沒有回報。所以,

((lambda (len) 
    (lambda (l) 
    (cond 
     ((null? l) 0) 
     (else (+ 1 (len (cdr l))))))) 
eternity) 

是一個函數調用返回函數(lambda (l) …)如果所謂的對空列表返回0,並進入一個非空列表的無限循環。

從程序分析的角度來看,值得注意的是其他值不會進入死循環。例如,如果你用一個字符串調用它,那麼(cdr l)將是一個錯誤。

2

就像你說的那樣,這是一個定義長度函數的部分函數,​​它只爲空列表完成。但是這還沒有涉及y- combinator部分,它不是一個匿名函數自己調用的例子。

l是一個原子列表,它是在評估(lambda (len) ...)時返回的函數的參數。

len是一個作爲參數傳遞給外部lambda的函數。

外部表達式創建一個帶有eternity作爲參數的lambda表達式。外層lambda返回一個通過評估內層lambda創建的函數,返回的函數是以eternity作爲參數的東西。

如果代碼被傳遞給一個空列表(意味着包含整個第一部分,然後在另一組parens中包含'()),那麼它當然會評估爲0。 len永遠不會被評估。

如果代碼通過一個非空的lat,那麼它將嘗試評估len參數,並且您將獲得無限遞歸。