2010-01-14 17 views
5

Tôi đang làm việc với clojure và trong khi tôi đã dabbled với lisps trước, tôi gặp khó khăn khi tìm một cách sạch sẽ để làm cho tuyên bố trong tuyên bố cond. Ví dụ, hãy xem xét các chức năng sau:để cho bên trong cond

(defn operate-on-list [xs] 
    (let [[unpack vector] (first xs)] 
    (cond 
     [(empty? xs) 'empty 
     unpack vector 
     :else (operate-on-list (rest xs))]))) 

Đó là một hoạt động đệ quy khá tiêu chuẩn trên một danh sách, nhưng nó cần phải làm một số công việc về phần tử đầu tiên trong danh sách trước khi nó hoạt động với những nội dung. Vấn đề, tất nhiên, là danh sách có thể trống.

Trong ví dụ này, nó sẽ không khó để thay đổi unpack-((first xs) 0)vector-((first xs) 1), nhưng điều này nhanh chóng trở nên xấu xí nếu nhiều việc cần được thực hiện trên (xs đầu tiên).

Có cách nào hiệu quả để sử dụng lệnh tuyên bố một cách thông qua lệnh cond không?

Cảm ơn.

-Nate

+0

Hi - nó không rõ ràng cho tôi những gì bạn đang cố gắng để đạt được ở đây. Bạn có thể tìm thấy http://www.assembla.com/spaces/clojure/tickets/200 và http://groups.google.com/group/clojure/browse_thread/thread/c1097ce07506fc39 thú vị này, vui lòng xem xét chức năng được cho là gì để làm trong câu hỏi của bạn, và một số ví dụ đầu vào và đầu ra. Cú pháp không giống như một câu lệnh cond hợp lệ vì phần thân của cond được bọc trong một vectơ. –

Trả lời

11

Trong những trường hợp như thế này, bạn tốt nhất nên sử dụng if-let:

(defn operate-on-list [xs] 
    (if-let [[unpack v] (first xs)] 
    (cond 
     unpack v 
     :else (operate-on-list (rest xs))))) 

Mã này đi các trao danh sách seq-thể (danh sách, vectơ, mảng ...) của vectơ và trả về phần tử thứ hai của vectơ đầu tiên có phần tử đầu tiên là đúng (nghĩa là không false hoặc nil). nil được trả về nếu không tìm thấy vectơ như vậy.

Lưu ý rằng vector là chức năng tích hợp, vì vậy tôi đã chọn v làm tên biến, chỉ trong trường hợp cần sử dụng chức năng trong cơ thể phát sinh trong tương lai. Quan trọng hơn, bạn đang sử dụng quá nhiều dấu ngoặc trong cú pháp cond của bạn; đã được sửa trong phiên bản này.

CẬP NHẬT: Hai điều bổ sung đáng chú ý về if-let:

  1. Cách if-let công trình, nếu (first xs) sẽ xảy ra là nil (false sẽ là như nhau), các destructuring ràng buộc không bao giờ xảy ra, vì vậy Clojure sẽ không phàn nàn về việc không thể ràng buộc nil đến [unpack v].

  2. Ngoài ra, if-let chấp nhận một khoản khác (trong đó bạn không thể đề cập đến các biến bị ràng buộc trong if-let bindings vector - mặc dù nếu bạn đang ở trong mệnh đề khác, bạn biết họ ở đâu false hoặc nil anyway).

+2

Xem thêm 'khi-let' là thành ngữ hơn khi bạn chỉ có một nhánh. – kotarak

+0

Lưu ý thứ hai: lưu ý rằng 'if-let' hoạt động ở đây, bởi vì danh sách được cho là chứa các vectơ. Nói chung '(khi-let [x (first s)] ...)' là * không * thay thế cho '(khi-let [s (seq s)] (cho [f (s đầu tiên)] ...)) '. – kotarak

2

Sắp xếp như thế này, với một let bên trong phạm vi của cond?

(defn operate-on-list [list] 
    (let [ el_first (first list) ] 
    (cond 
     (nil? el_first) (println "Finished") 
     :else (do 
     (let [ list_rest (rest list) ] 
       (println el_first) 
       (operate-on-list list_rest)))))) 

(operate-on-list '(1 2 3)) 

Đầu ra là:

1 
2 
3 
Finished 
+4

'do' của bạn là thừa. –

+0

@Brian Carper: bạn nói đúng; bạn có thể đơn giản bỏ qua. Đó là một sự nôn nao của Elisp trong phần tôi (đặc biệt là progn). –

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