2011-11-19 37 views
7

Hãy tưởng tượng tôi đã xác định một thừa đệ quy trong Mathematica, như thế này:Trong Mathematica, tại sao nó thay thế trong một hàm đệ quy không kết thúc?

Clear[fact] 
fact[0] = 1 
fact[n_] := n fact[n - 1] 

Đánh giá thực tế [10] khẳng định rằng chức năng hoạt động và chấm dứt.

Một chút ví dụ chủ yếu, nhưng nó phục vụ mục đích của nó trong câu hỏi này. Trên thực tế, câu hỏi của tôi liên quan đến định nghĩa chức năng đệ quy nói chung anyway.

tôi mong đợi đánh giá thay thế sau để chấm dứt cũng như:

x fact[x-1] /. x -> 2 

Alas, nó chạy vào một giới hạn độ sâu đệ quy:

$RecursionLimit::reclim: Recursion depth of 256 exceeded. 

tôi mong đợi để xem một cái gì đó như:

2 fact[2-1] 

hoặc chỉ giá trị

2 

UPDATE: Một định nghĩa đệ quy thay thế thực tếkhông công việc như mong đợi:

Clear[fact] 
fact[n_] := If[n < 1, 1, n fact[n - 1]] 

Nhưng thực tế này (ý định chơi chữ ;-) làm cho nó thậm chí còn bí ẩn hơn với tôi: Tại sao nó cư xử rất khác nhau?

Câu hỏi của tôi là hai khía cạnh:

  1. Ngay cả với built-in giúp đỡ và tìm kiếm trên net cho manh mối, tôi không thể giải thích tại sao Mathematica khẳng định trong, rõ ràng, giữ kết quả mang tính biểu tượng, chứ không phải là đánh giá kết quả 'trung gian' và chấm dứt độc đáo. Ai mạo hiểm một giải thích khả thi?

  2. Làm cách nào tôi có thể thuyết phục Mathematica thực hiện theo yêu cầu của tôi (Ngoài việc sử dụng phương án thay thế bằng cách sử dụng Nếu [])?

Tôi thực sự bối rối vì điều này và tôi thực sự hy vọng một người nào đó có thể giúp tôi.

/Twan

Trả lời

6

Cố u[x_] := x; Trace[x*u[x] /. x -> 2], nó đầu tiên đánh giá xu[x]. Trong trường hợp của bạn, sau đó, trước tiên nó sẽ cố gắng để đánh giá fact[x-1] trước khi thay thế x bằng 2 và đạt đến giới hạn đệ quy.

Attributes[ReplaceAll] cho thấy rằng nó không có thuộc tính HoldFirst, do đó, nó bắt đầu bằng cách đánh giá đối số đầu tiên của nó. Ví dụ,

[email protected][Hold[x*fact[x - 1]], x -> 2] 

cung cấp cho các dự 2, vì nó giữ đối số đầu tiên, thay thế, sau đó giải phóng các tổ chức, như bạn mong muốn.

Một cách khác để làm điều đó là

Unprotect[ReplaceAll] 
SetAttributes[ReplaceAll, HoldFirst] 
ReplaceAll[x*fact[x - 1], x -> 2] 

nhưng không làm điều này.

Chắc chắn một người nào đó sẽ sớm giải thích rõ hơn.

EDIT: Đáp lại câu hỏi thêm là tại sao

Clear[factif] 
factif[n_] := If[n < 1, 1, n factif[n - 1]] 

không dẫn đến đệ quy vô hạn: được xác định theo cách này, factif[x] đánh giá để If[x < 1, 1, x factif[x - 1]], vì x<1 không thể được đánh giá. Vì vậy, nó vẫn theo hình thức này sau khi đánh giá nỗ lực của đối số đầu tiên của ReplaceAll, sau đó thay thế xảy ra, vv

+0

Aha, điều đó có ý nghĩa: Mathematica đầu tiên đánh giá LHS của /. và _then_ thực hiện việc thay thế.Và với Hold [] bạn có thể hoãn đánh giá 'háo hức' đó. Cảm ơn câu trả lời tuyệt vời: hiệu quả, có liên quan, rõ ràng và ngắn gọn! Lời khen của tôi – nanitous

+0

@nanitous Chúc mừng! Nếu một trong ba câu trả lời không trả lời câu hỏi của bạn, bạn có thể đánh dấu câu trả lời đó là câu trả lời được chấp nhận để câu trả lời xuất hiện ở đầu (và nó mang lại sự nổi tiếng cho người trả lời). – acl

+0

cảm ơn vì đã chỉ ra điều đó! – nanitous

5

này là bởi vì bạn đang đánh giá này:

fact[x-1] 

trước khi thay thế sẽ xảy ra. Chỉ cần làm fact[x-1] và bạn gặp lỗi.

Bạn có thể sửa chữa chức năng fact bạn như vậy:

Clear[fact] 
fact[0] = 1 
fact[n_Integer?Positive] := n fact[n - 1] 

Sau đó x fact[x - 1] /. x -> 2 lợi nhuận 2 mà có vẻ đúng.

Hãy nhớ rằng mẫu đối số chức năng của bạn fact[n_]cực kỳ chung. Ví dụ, nó cho phép một cái gì đó như fact[Integrate[Sin[x], x]] để đánh giá, mà có lẽ không phải là một cái gì đó bạn dự định. Sử dụng fact[n_Integer] chính xác hơn nhiều và sẽ cho phép chức năng fact hoạt động theo cách bạn muốn.

Nếu bạn muốn xác định chức năng này thậm chí còn tốt hơn, bạn có thể làm một cái gì đó như:

Clear[fact] 
fact::nicetrybuddy = "fact[``] is not defined."; 
fact[0] = 1 
fact[n_Integer?Positive] := n fact[n - 1] 
fact[n_] := (Message[fact::nicetrybuddy, n]; $Failed) 

Vì vậy mà một cái gì đó giống như fact["x"] sẽ thất bại với một thông điệp:

fact::nicetrybuddy: fact[x] is not defined. 
+0

Ý tưởng hay để thêm mệnh đề câu trả lời! Tôi sẽ phải nhớ điều đó. – nanitous

1

Những câu trả lời khác là chính xác : fact đánh giá trước khi đối số của nó được thay thế. Vấn đề quan trọng là bạn đã xác định fact với đầu vào số nguyên trong tâm trí, và đã không cung cấp một điều kiện đầu cuối cho đầu vào không nguyên. Thay vào đó, nếu bạn đã thực hiện

Clear[fact] 
fact[0] = 1 
fact[n_Integer?Positive] := n fact[n - 1] 

Sau đó, fact sẽ không được đánh giá trước khi có thứ gì đó khớp với số nguyên dương.

Bạn có thể cần phải quấn câu lệnh thay thế của mình trong Evaluate để sau đó kích hoạt định nghĩa cho fact sau khi thay thế đối số của nó.

Một phương pháp khác có thể được sử dụng một chức năng tinh khiết:

# fact[#-1]& @ 2 

Đó không nên đánh giá sớm.

+0

Tôi đang chạy một mô phỏng lớn ngay bây giờ (400.000 bộ lọc Hodrick-Prescott!) Vì vậy tôi đã không kiểm tra đề xuất cuối cùng đó với hàm thuần túy. – Verbeia

+0

Tôi đã xem xét điều này. Nhưng tôi đã thử nghiệm với các hàm đệ quy khác nhau, ví dụ: cho danh sách. Và tôi đã gặp cùng một hành vi. Vì vậy, tôi đã đăng câu hỏi chung chung như tôi có thể. Nhưng một ví dụ không làm cho mọi thứ cụ thể trở lại. Xin lỗi vì chuyện đó. – nanitous

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