2012-01-21 38 views
6

Tôi đang cố gắng lấy Lisp làm ngôn ngữ mới của mình, và tôi đang gặp một số vấn đề về cách thực hiện các phần của hàm hoạt động trên mỗi phần tử của danh sách được truyền cho nó.defun với một danh sách như là đối số

Đối với mục đích của việc học làm thế nào để làm được việc này, tôi đang cố gắng để viết một hình thức khá cơ bản của bộ phận không tiếng kêu khi một trong những yếu tố của danh sách là 0 (nhưng thay vì chỉ trả về 0)

(defun divtest (elements) 
    (dolist (x elements) 
    (if (zerop x) 0()) 
    (/ elements))))) 

tôi cố gắng chạy này như:

(divtest '(20 2 5)) 

nào mang lại:

*** - /: (20 2 5) is not a number 

Điểm thất bại dường như bắt nguồn từ thực tế là tôi không "giải nén" các phần tử trong danh sách trước khi chuyển chúng đến hàm (trong trường hợp này, không phải/cũng không phải là dolist hoạt động như dự định, vì x không bao giờ đánh giá 0). Nếu tôi đúng, ai đó có thể cho tôi biết cách thực hiện "trích xuất" này?


Lưu ý: Câu hỏi này có liên quan đến one that I've asked earlier, nhưng như tôi không rõ ràng về những phần của câu trả lời trước thực sự cho phép nó hoạt động như dự định với vấn đề cụ thể này tôi quyết định đi sâu hơn vào những điều cơ bản

Trả lời

5

/ lấy làm đối số một hoặc nhiều số, nhưng trong mã của bạn, bạn đang chuyển một danh sách - rõ ràng điều này sẽ không hoạt động. Chức năng apply là bạn của bạn ở đây - (apply #'foo a b (list c d e)) tương đương với (foo a b c d e). Lưu ý các đối số cho apply giữa chức năng sử dụng và danh sách cuối cùng là tùy chọn, vì vậy (apply #'/ '(20 2 5)) tương đương với (/ 20 2 5).

Ngoài ra, nỗ lực xóa số không sẽ không hoạt động. dolist đang đánh giá nội dung của nó cho từng mục trong danh sách đối số elements, nhưng bạn không thực sự làm bất cứ điều gì để thay đổi nội dung của elements (kết quả đánh giá cơ thể dolist s không được gán lại cho phần tử nguồn như bạn mong đợi).

Các chức năng remove-if (và đối tác phá hoại của nó, delete-if) là những gì bạn đang tìm kiếm. Phần sau đây cho thấy cách sử dụng nó (phải mất rất nhiều đối số tùy chọn mà bạn không cần phải lo lắng về mục đích này).

(defun divtest (elements) 
    (apply #'/ (remove-if #'zerop elements))) 

Cũng lưu ý rằng điều này sẽ không cư xử một cách chính xác nếu danh sách elements có không như yếu tố đầu tiên của mình (giả sử tôi hiểu những gì của hàm nghĩa là để làm). Vì vậy, thay vào đó bạn có thể muốn một cái gì đó như

(defun divtest (elements) 
    (apply #'/ (first elements) (remove-if #'zerop (rest elements)))) 

Xem Hyperspec để biết thêm chi tiết.

+2

sử dụng REDUCE thay vì ÁP DỤNG –

+0

Chỉ tò mò: tiện ích đó sẽ là gì? – Hugh

+0

theo cách này bạn có thể xử lý các danh sách dài tùy ý và không chỉ các danh sách dài CALL-ARGUMENT-LIMIT (độ dài CL chuẩn). Lisp thông thường có số lượng đối số phụ thuộc thực hiện tối đa. Con số này phải từ 50 trở lên. Điều này có nghĩa là việc triển khai thực hiện chỉ cần hỗ trợ 50 đối số (hoặc nhiều hơn). Vì vậy, hàm trên của bạn có thể thất bại trong một số triển khai trong đó danh sách các số dài hơn số đối số gọi hàm/cho phép. –

0

Hãy thử (apply/elements) thay cho (/ elements). Tôi nghĩ rằng (?) Mà nên làm việc trong hầu hết các phương ngữ của Lisp.

+0

Bạn sẽ cần phải trích dẫn rằng '/' trừ khi bạn đã chỉ định một chức năng để '/' 's cell dữ liệu. – Hugh

1

Hoặc bạn có thể viết nó như thế này

(defun divtest (elements) 
    (if (member 0 elements) 
     0 
     (apply #'/ elements))) 
1
(block exit 
    (reduce #'/ '(1 2 3 0 5) 
      :key (lambda (x) 
       (if (zerop x) 
        (return-from exit 0) 
        x)))) 
Các vấn đề liên quan