12

Một số ví dụ về ngôn ngữ phạm vi động là gì? Và lý do để chọn thiết kế đó là gì? Có phải vì nó dễ thực hiện không?Bên cạnh Logo và Emacs Lisp, các ngôn ngữ động khác là gì?

+0

Ngày xửa ngày xưa, tất cả các phiên bản Lisp mà tôi biết đều có phạm vi động. elisp là một trong những người sống sót cuối cùng của thời gian đó. –

Trả lời

3

Vâng, có một loạt các trang web thảo luận về chuyên môn và con của, vì vậy tôi sẽ không đến đó.

Một ngôn ngữ thú vị có một số tính năng giống với phạm vi động là XSLT; mặc dù các mẫu và biến tương tự của XSLT và các kiểu tương tự đều bị xáo trộn, XSLT dĩ nhiên là tất cả về XML - và vị trí hiện tại trong cây xml được "tự động dò tìm" theo nghĩa là nút ngữ cảnh là toàn cầu và do đó biểu thức XPath được đánh giá không theo phạm vi từ vựng của XSLT nhưng theo đánh giá năng động của nó.

7

Mathematica là một ngôn ngữ khác được sắp xếp động, thông qua cấu trúc Block. Điều này thực sự khá hữu ích khi làm việc với các công thức. Nó cho phép bạn viết những thứ như

In[1]:= expr = a*t^2 + b*t+ c; 

In[2]:= Block[{a = 1, b = -1, c = 2}, Table[expr, {t, 5}]] 
Out[2]= {2, 4, 8, 14, 22} 

đó sẽ không làm việc ở tất cả nếu biến như at được scoped lexically. Nó hoạt động đặc biệt độc đáo với hệ thống viết lại quy tắc của Mathematica, trong đó, trong số những thứ khác, để các biến không được đánh giá (như các biểu thức biểu tượng) nếu nó không có định nghĩa hiện tại cho chúng.

Mathematica có thể giả mạo phạm vi từ vựng với cấu trúc Module, nhưng điều này thực sự là viết lại biểu thức dưới dạng biểu tượng mới, bị cáo buộc duy nhất (bạn có thể gây ra xung đột nếu bạn dự đoán biểu tượng tiếp theo sẽ là gì trong hầu hết các trường hợp). Điều này có nghĩa

Module[{x = 4}, 
    Table[x * t, {t, 5}]] 

sẽ được biến thành một cái gì đó như thế này:

Block[{x$134 = 4}, 
    Table[x$134 * t, {t, 5}] 

Emacs Lisp, trong một trong các thư viện của nó, có một cấu trúc (thực sự là một vĩ mô Lisp) gọi lexical-let mà kéo chính xác các trick cùng đến phạm vi từ vựng giả.

Có những ưu điểm về hiệu suất đối với phạm vi từ vựng thực khi bạn biên dịch ngôn ngữ mà bạn không nhận được với từ vựng giả của ELisp hoặc Mathematica, vì bạn cần ánh xạ giữa biến động và giá trị hiện tại của nó làm tra cứu (thông qua một bảng băm hoặc danh sách tài sản hoặc một cái gì đó) và các lớp bổ sung của indirection.

CHỈNH SỬA: Nếu bạn chỉ có các biến từ vựng, bạn có thể giả mạo phạm vi động bằng cách lưu trữ giá trị ban đầu của biến toàn cầu, từ vựng vào phạm vi và đảm bảo rằng giá trị cũ được khôi phục khi thoát khỏi phạm vi. Để đảm bảo điều đó, bạn sẽ cần một số thứ như số UNWIND-PROTECT của Lisp hoặc một khối finally. Tôi đã nhìn thấy điều này được thực hiện bằng cách sử dụng C++ destructors là tốt, chủ yếu là một bài tập.

9

Ngôn ngữ phạm vi động được thực hiện dễ dàng hơn nhiều. Để truy cập các biến không nằm trong khung bản ghi/khung hoạt động hiện tại, một biến chỉ theo các liên kết điều khiển. Liên kết truy cập tĩnh/từ vựng sau đó không cần thiết, làm cho khung stack nhỏ hơn.

Biến động có thể là "không thể đoán trước" trong thời gian chạy, bởi vì cần phải biết thứ tự các khung hình thực tế sẽ biết biến nào sẽ được sử dụng. Thông tin này không có sẵn bằng cách chỉ xem xét cấu trúc tĩnh của mã. Người ta có thể dễ dàng bị bắt nếu biểu đồ cuộc gọi thực tế của chương trình không dễ dự đoán tại thời điểm triển khai.Thats lý do tại sao hầu hết các ngôn ngữ ngày nay có phạm vi tĩnh (hầu hết các hệ thống ngoại lệ, năng động vì đây là thực tế nhất).

Tuy nhiên, trong một số trường hợp, các biến phạm vi động là rất hữu ích. Ví dụ khi chuyển hướng đầu ra, bạn có thể sử dụng các biến động đặt đầu ra tiêu chuẩn cho mã cục bộ và tất cả mã được gọi từ đó.

(let ((*standard-output* *some-other-stream*)) 
(stuff)) 

Trong ví dụ phổ biến này (từ Seibel), đầu ra chuẩn bị ràng buộc vào luồng khác trong khoảng thời gian cho phép, (bên trong dấu ngoặc đơn kèm theo). Khi thực hiện rời khỏi let, nó quay trở lại bất cứ điều gì nó đã được trước. Xem http://gigamonkeys.com/book/variables.html Peter Seibels cuốn sách miễn phí và xuất sắc, Thực hành Common Lisp, để có một cuộc thảo luận tốt. Trong các từ riêng của Seibels:

Ràng buộc động làm cho các biến toàn cầu dễ quản lý hơn, nhưng điều quan trọng cần lưu ý là chúng vẫn cho phép hành động ở khoảng cách xa. Ràng buộc một biến toàn cầu có hai ở một hiệu ứng khoảng cách - nó có thể thay đổi hành vi của mã hạ lưu, và nó cũng mở ra khả năng mã hạ lưu sẽ gán một giá trị mới cho một ràng buộc được thiết lập cao hơn trên ngăn xếp. Bạn chỉ nên sử dụng các biến động khi bạn cần tận dụng một hoặc cả hai đặc điểm này.

3

Phạm vi động/dễ thực hiện hơn với người phiên dịch. Hầu hết các thông dịch viên Lisp sớm đều sử dụng phạm vi động. Sau vài năm phạm vi từ vựng đã được tìm thấy có một lợi thế, nhưng lần đầu tiên được thực hiện chủ yếu trong các trình biên dịch Lisp. Một số triển khai đã xuất hiện rằng phạm vi động được triển khai trong mã được giải thích và phạm vi từ vựng trong mã được biên dịch. Một số cung cấp một ngôn ngữ đặc biệt xây dựng để cung cấp bao đóng. Các phương ngữ Lisp như Scheme và Common Lisp được yêu cầu sau đó là không có sự khác biệt giữa mã được biên dịch và biên dịch và do đó các giải thích dựa trên diễn giải cũng phải thực hiện phạm vi từ vựng.

Triển khai Smalltalk sớm triển khai phạm vi động. Tất cả các loại triển khai phương ngữ Lisp đều triển khai phạm vi động (Interlisp, UCI Lisp, Lisp Machine Lisp, MacLisp, ...).

Hầu như tất cả các phương ngữ Lisp mới trong 20 năm qua sử dụng phạm vi từ vựng theo mặc định hoặc thậm chí độc quyền. Một số ấn phẩm đã mô tả chi tiết cách triển khai Lisp với phạm vi từ vựng - vì vậy không có lý do gì để không sử dụng phạm vi từ vựng.

2

Tất cả ngôn ngữ shell (bash, ksh, v.v.) đều sử dụng phạm vi động.

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