2009-09-06 25 views
7

Tôi mới sử dụng và viết một vài chương trình đơn giản để làm quen với nó. Một trong những điều tôi đang làm là viết một phiên bản đệ quy và lặp lại của một phương pháp giai thừa. Tuy nhiên, tôi đã gặp một vấn đề và dường như không thể giải quyết nó.Cảnh báo Lisp: xx không được khai báo cũng như bị ràng buộc, nó sẽ được xử lý như thể nó được khai báo ĐẶC BIỆT

Tôi đã gặp lỗi tương tự tại Lisp: CHAR is neither declared nor bound nhưng giải pháp không thực sự đạt được, ngoài OP nhận ra anh ta đã tạo "lỗi nhập". Trong REPL tôi có thể sử dụng hàm setf và nó hoạt động tốt. Tôi cũng đang sử dụng LispBox với các emacs. Tôi sẽ đánh giá cao bất kỳ lời đề nghị!

(defun it-fact(num) 
    (setf result 1) 
    (dotimes (i num) 
    (setf result (* result (+ i 1))) 
) 
) 

CẢNH BÁO trong lĩnh vực CNTT-SỰ THẬT: KẾT QUẢ không phải là tuyên bố cũng không bị ràng buộc, đó sẽ được coi như thể nó đã được tuyên bố ĐẶC BIỆT.

+1

Xem http://www.cs.cmu.edu/Groups/AI /html/faqs/lang/lisp/part1/faq-doc-4.html, đặc biệt là ví dụ "GOOD:". Mọi người ở đây khá thân thiện theo cách nào đó, nhưng mã của bạn dễ đọc hơn nếu nó thụt vào giống như mã Lisp điển hình. Chúc mừng! – Alec

Trả lời

5

Bạn cần phải ràng buộc 'kết quả' biến - sử dụng 'let', ví dụ - trước khi bắt đầu sử dụng nó:

(defun it-fact(num) 
    (let ((result 1)) 
    (dotimes (i num) 
     (setf result (* result (+ i 1)))))) 

Để biết chi tiết thêm tác bạn có thể muốn đọc this ...

+0

Ồ tôi hiểu rồi. Tôi đã thử 'let' trước đây nhưng tôi đã sử dụng nó như thể nó đã được setf, và tôi đã không bao gồm các vòng lặp dotimes bên trong dấu ngoặc đơn của let. Tôi đoán rằng phải làm với phạm vi hoặc một cái gì đó. Cảm ơn vì đã giúp mọi người! – Aaron

+0

Nghiêm túc, thụt lề mã của bạn đúng cách. –

+0

Vì tôi chủ yếu là một lập trình viên java, bạn có thể dễ dàng thấy lý do tại sao tôi đưa xuống dấu ngoặc đơn (xem chúng như không có gì hơn là dấu ngoặc đơn). Tôi đã từng quen với việc đặt các phụ huynh đóng cửa trên một dòng nhờ vào các ví dụ được trình bày ở đây, do đó, nó "nghiêm túc" không phải là lớn của một thỏa thuận. Cảm ơn anway :) – Aaron

5

Trong Lisp, các biến cục bộ phải được khai báo rõ ràng với LET hoặc các dạng khác tạo các biến cục bộ. Điều đó khác với ví dụ: Python hoặc JavaScript trong đó gán cho biến sẽ tạo biến trong phạm vi từ vựng hiện tại.

dụ của bạn có thể được viết lại như thế này:

(defun it-fact(num) 
    (let ((result 1)) 
    (dotimes (i num) 
     (setf result (* result (+ i 1)))))) 

Một bình luận off-topic: không có điểm trong việc đưa ngoặc đóng trên dòng riêng biệt.

6

Có một vài điều sai trái hoặc không tốt như vậy Lisp phong cách:

(defun it-fact(num)      ; style: use a space before (
    (setf result 1)      ; bad: variable result is not introduced 
    (dotimes (i num) 
    (setf result (* result (+ i 1)))  ; bad: extra addition in each iteration 
)          ; style: parentheses on a single line 
)          ; bad: no useful return value 

Một phiên bản thể:

(defun it-fact (num) 
    (let ((result 1))      ; local variable introduced with LET 
    (loop for i from 1 upto num   ; i starts with 1, no extra addition 
     do (setf result (* result i))) 
    result))        ; result gets returned from the LET 
+2

Cảm ơn bạn đã đề xuất! Vâng, tôi nhận ra rằng dotimes bắt đầu từ 0 và nếu tôi không tăng nó trong phép nhân nó sẽ luôn luôn trở về 0 ... Vòng lặp của bạn trông dễ đọc hơn. Tôi nghĩ rằng tôi đặt dấu ngoặc đơn trên mỗi dòng như vậy bởi vì tôi vẫn còn được sử dụng để niềng răng từ c + +/java, nhưng tôi sẽ cố gắng áp dụng thực hành của bạn cho lisp. Rất tiếc, tôi đã bỏ qua sự trở lại, cảm ơn vì đã chỉ ra những điều này! – Aaron

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