2010-07-09 5 views
14

Tôi đã nghiên cứu Đề án gần đây và đi qua một chức năng được xác định theo cách sau:Trong Đề án nhằm mục đích (let ((cdr cdr))

(define remove! 
    (let ((null? null?) 
      (cdr cdr) 
      (eq? eq?)) 
    (lambda ... function that uses null?, cdr, eq? ...) 

mục đích null ràng buộc là gì ? null? hoặc cdr để CDR, khi chúng được xây dựng trong các chức năng có sẵn trong một định nghĩa chức năng mà không có một khối let?

Trả lời

30

Trong sơ đồ R5RS đơn giản, không có hệ thống mô-đun nào - chỉ có sự to lớn. thermore, tâm lý là tất cả mọi thứ có thể được sửa đổi, vì vậy bạn có thể "tùy chỉnh" ngôn ngữ bất kỳ cách nào bạn muốn. Nhưng không có một hệ thống mô-đun, điều này không hoạt động tốt. Ví dụ, tôi viết

(define (sub1 x) (- x 1)) 

trong một thư viện mà bạn nạp - và bây giờ bạn có thể xác định lại -:

(define - +) ; either this 
(set! - +) ; or this 

và bây giờ bạn vô tình đã phá vỡ thư viện của tôi mà dựa vào sub1 decrementing đầu vào của nó bởi một và kết quả là cửa sổ của bạn sẽ tăng lên khi bạn kéo chúng xuống hoặc bất kỳ thứ gì.

Cách duy nhất xung quanh này, được sử dụng bởi một số thư viện, là để "lấy" định nghĩa liên quan của hàm subtraction, trước khi ai đó có thể sửa đổi nó:

(define sub1 (let ((- -)) (lambda (x) (- x 1)))) 

Bây giờ mọi thứ sẽ làm việc "nhiều mỹ ", vì bạn không thể sửa đổi ý nghĩa của hàm sub1 của tôi bằng cách thay đổi -. (Ngoại trừ ... nếu bạn sửa đổi nó trước khi bạn tải thư viện của mình ...)

Dù sao, do kết quả này (và nếu bạn biết rằng - là thư gốc khi thư viện được tải), một số trình biên dịch sẽ phát hiện điều này và thấy rằng cuộc gọi - luôn là hàm trừ thực tế và do đó chúng sẽ gọi nội tuyến tới nó (và nội tuyến gọi - cuối cùng có thể dẫn đến mã lắp ráp để trừ hai số, vì vậy đây là tăng tốc độ lớn). Nhưng như tôi đã nói trong bình luận ở trên, điều này trùng hợp hơn với lý do thực sự ở trên.

Cuối cùng, R6RS (và một số triển khai chương trình trước đó) đã sửa lỗi này và thêm hệ thống thư viện, do đó không sử dụng được mẹo này: mã sub1 là an toàn miễn là mã khác trong thư viện của nó không được xác định lại - một cách nào đó, và trình biên dịch có thể tối ưu hóa một cách an toàn mã dựa trên điều này. Không cần thủ thuật thông minh.

+0

cảm ơn bạn đã phản hồi kỹ lưỡng! – redwoolf

2

đó là một tối ưu hóa tốc độ. truy cập biến địa phương thường nhanh hơn các biến toàn cục là.

+0

Bạn có thể giải thích chi tiết hơn không? Dường như quá trình gắn kết với let sẽ mất nhiều thời gian như một tra cứu. – redwoolf

+0

@redwoolf: Tra cứu khi liên kết với 'let' chỉ xảy ra một lần, nhưng' cdr' có thể được sử dụng (và tra cứu) nhiều, nhiều lần trong hàm. – Teddy

+3

Trong khi điều này có thể có một lợi ích tốc độ trong một số triển khai, nó chỉ là một sản phẩm phụ của lý do quan trọng hơn để làm điều này. Tôi sẽ viết về điều đó trong một câu trả lời riêng biệt. –