2010-04-29 25 views
7

Như đã được chỉ ra trong phạm vi post gần đây không hoạt động như mong đợi bên trong Mô-đun.Tại sao Mathematica phá vỡ các quy tắc phạm vi bình thường trong Mô-đun?

Một ví dụ từ chủ đề đó là:

Module[{expr}, 
expr = 2 z; 
    f[z_] = expr; 
    f[7]] 
(*2 z*) 

Nhưng sau hoạt động gần như mong đợi.

Module[{expr}, 
expr = 2 z; 
    [email protected]@{f[z_], expr}; 
    f[7]] 
(*14*) 

Xem xét thiết kế ngôn ngữ nào khiến wolfram chọn chức năng này?

Chỉnh sửa: Xem nhận xét đầu tiên của Jefromi Tôi đã thay đổi z từ biến cục bộ thành không và quên thay đổi đầu ra. Nó không ảnh hưởng đến vấn đề.

Chỉnh sửa2: Điểm của Michael Pilat có vẻ là Khối và Mô-đun có các chức năng khác nhau. Tôi nghĩ rằng tôi hiểu quan điểm của anh ấy, nhưng tôi nghĩ rằng đó là trực giao với câu hỏi của tôi. Đây là bản cập nhật.

tôi có thể sử dụng đoạn mã sau vào cấp độ toàn cầu trong một máy tính xách tay:

expr = 2 z; 
f[z_] = expr; 
f[7] 
(*output: 14*) 

Nhưng khi tôi đặt khối mã tương tự thành một Module và làm expr địa phương nó tạo ra một đầu ra khác nhau.

Clear[f]; 
Module[{expr}, 
expr = 2 z; 
f[z_] = expr; 
f[7]] 
(*output: 2z*) 

Nếu bạn theo dõi ở trên Mô-đun gọi bạn thấy rằng Set [f [z_], expr] được viết lại thành [f [z $ _, expr]. Bây giờ chuyển đổi z-> z $ này xảy ra trên cả lhs và rhs của Set. Tuy nhiên nó xảy ra trước khi expr được đánh giá, điều này gây ra một kết quả khác nhau sau đó sẽ thu được ở mức toàn cầu.

Biến đổi z-> z $ dường như chỉ xảy ra khi các vần có biểu tượng cục bộ cho cuộc gọi Mô-đun.

Tại sao Mathematica chọn thay đổi cú pháp này trong cuộc gọi Mô-đun? Sự cân bằng thiết kế ngôn ngữ/triển khai thực hiện ở đây đã đưa ra quyết định này.

+0

Bạn đang sử dụng phiên bản toán học nào? Đầu tiên có thực sự cung cấp cho bạn z địa phương của mô-đun ('z $ 1776') thay vì chỉ' 2z' (đó là những gì tôi nhận được, sử dụng phiên bản 6.0.0). – Cascabel

+0

Hoặc là z cục bộ được tạo bởi kết hợp mẫu? – Cascabel

+1

Từ Trace, Mathematica quyết định rằng vì có một biến cục bộ trên RHS của tập, nó sẽ sử dụng biến cục bộ cho mẫu ('f [z $ _] = expr $ 64'). Trong tất cả các trường hợp khác tôi có thể nghĩ đến, khi RHS không chứa biến cục bộ, nó sử dụng 'f [z_] = ...'. Có lẽ có một số trường hợp đánh giá hợp lý trong đó hành vi này có ý nghĩa, nhưng tôi chắc chắn không thể nghĩ về nó. 1, và tôi hy vọng ai đó quản lý để trả lời. – Cascabel

Trả lời

2

Theo the documentation, Module có thuộc tính HoldAll, khiến tất cả mọi thứ bên trong Module duy trì trong tình trạng unevaluated, vì vậy expr của bạn không được đánh giá để 2 z trước expr được gán cho f[z_].

Bao bì các đối số thứ hai để Module trong Evaluate dường như giải quyết vấn đề:

In[1]:= Module[{expr}, Evaluate[expr = 2 z; 
    f[z_] = expr; 
    f[7]]] 

Out[1]= 14 

Ngoài ra, sử dụng Block thay vì Module công trình:

In[2]:= Block[{expr = 2 z}, 
f[z_] = expr; 
f[7]] 

Out[2]= 14 
+0

Bằng cách sử dụng Đánh giá mặc dù bạn đã tạo expr một biến toàn cầu thay vì một biến cục bộ. – Davorak

5

Tôi nghĩ rằng câu trả lời là khá đơn giản, nhưng tinh tế: Module là cấu trúc phạm vi từ vựng và Block là cấu trúc phạm vi động.

Các Blocks Compared With Modules hướng dẫn từ các tài liệu thảo luận về sự khác biệt:

Khi Phạm vi từ vựng được sử dụng, các biến được coi là địa phương đến một phần cụ thể của mã trong một chương trình.Trong phạm vi động, các giá trị của các biến là cục bộ cho một phần của lịch sử thực hiện của chương trình. Trong các ngôn ngữ được biên dịch như C và Java, có một sự phân biệt rất rõ ràng giữa "mã" và "lịch sử thực thi". Bản chất tượng trưng của Mathematica làm cho sự khác biệt này ít rõ ràng hơn, vì "mã" về nguyên tắc có thể được xây dựng một cách năng động trong quá trình thực thi chương trình.

Điều gì Module[vars, body] thực hiện là xử lý hình thức của phần thân biểu thức tại thời điểm mô-đun được thực thi dưới dạng "mã" của một chương trình Mathematica. Sau đó, khi bất kỳ vars rõ ràng xuất hiện trong "mã" này, nó được coi là địa phương. Block[vars, body] không nhìn vào biểu mẫu của nội dung biểu thức. Thay vào đó, trong suốt quá trình đánh giá của cơ thể, khối sử dụng các giá trị cục bộ cho các vars.

Nó cung cấp ví dụ giảm này:

In[1]:= m = i^2 

Out[1]= i^2 

(* The local value for i in the block is used throughout the evaluation of i+m. *) 
In[2]:= Block[{i = a}, i + m] 

Out[2]= a + a^2 

(* Here only the i that appears explicitly in i+m is treated as a local variable. *) 
In[3]:= Module[{i = a}, i + m] 

Out[3]= a + i^2 

Có lẽ điểm quan trọng là nhận ra rằng Module thay thế tất cả các trường hợp của i trong cơ thể mô-đun với một phiên bản cục bộ (ví dụ, i$1234) lexically, trước bất kỳ phần nào của mô-đun được đánh giá thực sự.

Do đó, nội dung mô-đun thực sự được đánh giá là i$1234 + m, sau đó i$1234 + i^2, sau đó a + i^2.

Không có gì bị hỏng, BlockModule được thiết kế để hoạt động khác nhau.

+0

Đó là gần với những gì tôi đã trả lời trong câu hỏi cuối cùng. Điểm lexically scoping một cái gì đó là để bạn có thể làm cho một số biến địa phương và lá mọi thứ khác không thay đổi. Mô-đun không để mọi thứ khác không thay đổi. Làm thế nào để thay đổi cú pháp có sẵn phục vụ mục đích của Mô-đun? Nhìn vào Dấu vết của các mô-đun trên một với f [z _] = expr và một với f [z_] = . Cái trước có z viết lại là z $ và z sau đó không thay đổi. Tại sao Mô-đun tương tác với phạm vi nội bộ bổ sung theo cách này? Có một số tiêu chí thiết kế ngôn ngữ mà tôi đang thiếu không? – Davorak

+0

Nếu Mô-đun không viết lại z là z $ trong trường hợp sau đó thì Set of f [z_] sẽ hoạt động vì nó sẽ có mặt bên của một câu lệnh mô-đun và cách mong đợi nó hoạt động. Cũng cảm ơn bạn. – Davorak

+0

Chỉ trong trường hợp nó không rõ ràng tôi không hiểu làm thế nào bạn ví dụ là nghĩa vụ phải áp dụng cho các ví dụ tôi cung cấp kể từ khi tất cả các Bộ trong ví dụ của tôi xảy ra trong tuyên bố Module và của bạn không. – Davorak

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