[英]Erlang function calls - Why does it not work to call self() as a direct argument?
[英]Why is it legal in a function definition to make self-call but illegal for a value?
計算機程序的結構和解釋(SICP)3.5.2引入了無限流:
(define ones
(cons-stream 1 ones))
此代碼在DrRacket中不起作用,錯誤如下:
一個:未定義; 在定義之前不能引用標識符
其他代碼如下:
(define (integers-starting-from n)
(cons-stream n
(integers-starting-from (+ n 1))))
(define integers (integers-starting-from 1))
產生錯誤:
交互禁用
(陷入無限循環?)
據我所知(SICP),實現無限流的關鍵是延遲評估:
(define (delay exp)
(lambda () exp))
(define (cons-stream a b)
(cons a
(delay b)))
有了這個用於cons-stream
,無限流仍然是非法的。
這樣的數據結構讓我想起了遞歸函數,在其定義中,自調用是合法的(在編譯中)是否在實際退出之內。
為什么值引用自身是非法的? 連參考都被推遲了?
其他編程語言可以支持無限流嗎?
如果沒有,它是關於處理器處理匯編語言的方式嗎? 數據堆棧的東西?
在創建過程時,在啟動過程主體時已經評估了參數。 因此delay
不會做任何事情,因為它已經在那時計算過了。 cons-stream
需要是一個宏。
DrRacket不是一種語言實現。 它是一個支持許多語言的IDE。 其中之一是SICP兼容性語言。 我使用DrRacket中的代碼管理您的代碼而不會出錯:
#!planet neil/sicp
(define ones
(cons-stream 1 ones))
(define (integers-starting-from n)
(cons-stream n
(integers-starting-from (+ n 1))))
(define integers (integers-starting-from 1))
它就像一個魅力。 DrRacket中的默認語言#!racket
也有流 ,但名稱不同:
#!racket
(define ones
(stream-cons 1 ones))
(define (integers-starting-from n)
(stream-cons n
(integers-starting-from (+ n 1))))
(define integers (integers-starting-from 1))
但是對於Scheme你應該使用SRFI-41,你可以使用#!racket
(使用(require srfi/41)
)和#!r6rs
(和R7RS-large完成時)
(import (rnrs)
(srfi :41))
(define ones
(stream-cons 1 ones))
(define (integers-starting-from n)
(stream-cons n
(integers-starting-from (+ n 1))))
(define integers (integers-starting-from 1))
要在#!racket
和#!r6rs
滾動自己的SICP流,可以使用define-syntax
(define-syntax stream-cons
(syntax-rules ()
((_ a d) (cons a (delay d)))))
請注意,RSFI-41和球拍擁有#!racket
的流庫會延遲stream-cons
兩個值,而不僅僅是SICP版本中的尾部。
這是因為在名稱綁定到值之前會計算define
的表達式。 它試圖評估(cons-stream 1 ones)
之前ones
被定義,從而引起錯誤。
這對函數來說效果很好的原因是函數的主體在函數時不被計算 。 也就是說,為了評估(lambda (x) (fx))
,語言返回一個函數而不查看它的主體。 以來
(define (f x) (f x))
是用於定義lambda的語法糖,同樣的邏輯適用。
您是否按上述方式自定義了cons-stream
? 如果你使cons-stream
成為正常函數,它將無法正常工作。 由於Scheme默認是嚴格的,因此在調用函數之前會計算參數。 如果cons-stream
是一個普通函數, b
在被傳遞給delay
之前會被完全評估,從而使你無限循環。
SICP中的cons-stream
是一種“特殊形式”而不是函數,這意味着它可以控制其參數的評估方式。
如果您使用內置於Racket中的stream-cons
和其他stream-
操作,您將獲得所需的行為。
最后,一些其他語言確實允許值參考自己。 一個很好的例子是Haskell,這是有效的,因為默認情況下一切都是懶惰的 。 這里有一個Haskell的片段定義ones
是那些無限名單。 (因為一切都很懶惰,Haskell列表就像Scheme流一樣):
ones = 1 : ones
這個定義適用於Racket:
(define ones
(cons-stream 1 ones))
...只要您提供延遲實施的cons-stream
作為特殊形式,這是SICP第3.5節的全部要點:
(define-syntax cons-stream
(syntax-rules ()
((_ head tail)
(cons head (delay tail)))))
添加上面的答案,為了確保代碼運行,您還應該像這樣定義delay
:
(define-syntax delay
(syntax-rules ()
((_ exp)
(lambda () exp))))
delay
以及cons-stream
必須定義為宏。
在另一個選項中,您可以調用在Racket中預定義的delay
而不是構建新的delay
。
但是不要這樣做:
(define (delay exp)
(lambda () exp))
編譯器將采用您的定義,因此程序在評估中崩潰:
交互禁用
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.