2010-10-13 16 views
8

Tôi đang đọc phần sau của SICPCâu hỏi về SICP chpt 4.1: Làm thế nào (phân tích expr) giúp tăng tốc độ eval?

http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-26.html#%_sec_4.1.7

Theo văn bản, việc chuyển đổi sau đây của eval sẽ cải thiện cung cấp một cải thiện hiệu suất, vì một biểu thức được đánh giá nhiều lần sẽ chỉ được phân tích một lần ?

(define (eval exp env) 
    ((analyze exp) env)) 

Dưới đây là một chức năng analyze đưa ra trong cuốn sách:

(define (analyze-if exp) 
(let ((pproc (analyze (if-predicate exp))) 
    (cproc (analyze (if-consequent exp))) 
     (aproc (analyze (if-alternative exp)))) 
    (lambda (env) 
     (if (true? (pproc env)) 
      (cproc env) 
       (aproc env))))) 

Tôi không hiểu tại sao cuốn sách nói rằng analyze sẽ chỉ chạy một lần. Không phải nội dung của eval, là ((analyze exp) env)) về cơ bản nói rằng mỗi lần eval được gọi, analyze sẽ được gọi với thông số exp? Điều này có nghĩa là analyze sẽ được gọi mỗi khi eval được gọi.

Tôi hiểu gì? Tôi sẽ đánh giá cao bất kỳ phản hồi nào, cảm ơn!

Trả lời

5

Thật vậy, mỗi khi bạn gọi eval với mã chương trình làm tham số, bộ đánh giá cú pháp sẽ được gọi. Tuy nhiên, khi một hàm bên trong mã đó gọi một hàm khác trong mã đó (hoặc, trong trường hợp đơn giản nhất, nó tự gọi bằng đệ quy), bên trong apply sẽ nhận được biểu thức được phân tích (đó là kết thúc hàm lambda) làm đối số , chứ không phải là một blob mã mà sẽ cần phải được phân tích cú pháp một lần nữa để được thực thi.

5

Câu trả lời của Gintautas là đúng, nhưng có thể một ví dụ là theo thứ tự. Giả sử bạn đã phát triển phương ngữ Đề cương có thể dựng vòng lặp

(do-n-times n expr) 

với ngữ nghĩa rõ ràng. Bây giờ, khi bạn gọi ngây thơ eval để đánh giá một vòng lặp chạy gấp mười lần

(eval '(do-n-times 10 (print 'hello))) 

sau đó nó sẽ phân tích cơ thể vòng mười lần. Với phiên bản eval tách phân tích khỏi đánh giá, thân vòng lặp là analyze d một lần, sau đó được đánh giá mười lần.

Giai đoạn phân tích trả về một quy trình, có thể hoặc không nhanh trong trình thông dịch Đề án của bạn. Tuy nhiên, nó có thể hình dung được tất cả các loại tối ưu hóa (phân tích mã chết, JIT compilation thành mã máy, v.v.).

2

câu trả lời của larsmans là cực kỳ tốt.

Là một câu trả lời bổ sung, người ta cũng có thể xem analyze(environ) dưới dạng hình thức được kết hôn là eval(expr, environ) trong đó thông số expr đã được chuyển trước. Trong SICP, bạn có thể đọc các mã ví dụ như:

(define (analyze-assignment exp) 
    (let ((var (assignment-variable exp)) 
     (vproc (analyze (assignment-value exp)))) 
    (lambda (env) 
     (set-variable-value! var (vproc env) env) 
     'ok))) 

Khi bạn nhìn thấy một let (([var] [preprocessed stuff])), đó là tiền xử lý được lưu trữ trong một đóng cửa cho đến khi nó là cần thiết sau khi environ được thông qua tại

.
Các vấn đề liên quan