2009-06-28 28 views
11

Tôi đang cố gắng tìm hiểu cách thực hiện thuật toán sau,Clojure Trong khi Loop

Tôi đọc từ luồng đầu vào tôi muốn tiếp tục đọc cho đến khi nó không phải là ký tự phân cách.

tôi có thể làm điều này trong java với một vòng lặp while nhưng tôi không thể có vẻ để tìm ra cách để làm điều đó trong clojure?

 
while 
    read 
    readChar != delimiter 

    do some processing.... 
end while 

Trả lời

10

Tôi không biết Clojure, nhưng có vẻ rằng, giống như Đề án, nó hỗ trợ "để cho vòng":

(loop [char (readChar)] 
    (if (= char delimiter) 
     '() 
     (do (some-processing) 
      (recur (readChar))))) 

Hy vọng điều này là đủ để giúp bạn bắt đầu. Tôi đã gọi http://clojure.org/special_forms#toc9 để trả lời câu hỏi này.

LƯU Ý: Tôi biết rằng Clojure không khuyến khích các tác dụng phụ, vì vậy có lẽ bạn muốn trả về một cái gì đó hữu ích thay vì '().

+0

Đúng về tác dụng phụ. Có thể thêm một bộ tích lũy vào vòng lặp để cho biết kết quả được xây dựng như thế nào? –

2

Tôi nghĩ ra điều này theo tinh thần của line-seq. Nó hoàn toàn lười biếng và trưng bày nhiều tính chất chức năng của Clojure hơn loop.

(defn delim-seq 
    ([#^java.io.Reader rdr #^Character delim] 
    (delim-seq rdr delim (StringBuilder.))) 
    ([#^java.io.Reader rdr #^Character delim #^StringBuilder buf] 
    (lazy-seq 
     (let [ch (.read rdr)] 
     (when-not (= ch -1) 
      (if (= (char ch) delim) 
      (cons (str buf) (delim-seq rdr delim)) 
      (delim-seq rdr delim (doto buf (.append (char ch)))))))))) 

Full paste.

+0

Phải là một cách ngắn hơn 'ta làm điều này. – Kzqai

1

Một vòng lặp while thường liên quan đến các biến có thể thay đổi, tức là chờ cho đến khi biến gặp một điều kiện nhất định; trong Clojure, bạn thường sử dụng tính năng đệ quy đuôi (mà trình biên dịch dịch thành vòng lặp while)

Sau đây không phải là giải pháp, nhưng biến thể của vòng lặp này có thể trợ giúp trong một số trường hợp:

(for [a (range 100) 
     b (range 100) 
     :while (< (* a b) 1000)] 
    [a b] 
) 

này sẽ tạo ra một danh sách tất cả các cặp của a và b cho đến khi(< (* a b) 1000). Đó là nó sẽ dừng lại ngay sau khi điều kiện được đáp ứng. Nếu bạn thay thế: trong khi với: khi nào, họ có thể tìm thấy tất cả của các cặp đáp ứng điều kiện, ngay cả sau khi tìm thấy một cặp không khớp.

5

Làm việc trên Clojure 1.3.0, và cho những gì nó có giá trị, bạn có thể viết vòng lặp while trong Clojure bây giờ bằng cách làm một cái gì đó giống như

(while truth-expression 
    (call-some-function)) 
+0

điều này dựa vào một số tác dụng phụ để làm cho biểu hiện sự thật cuối cùng đi sai. – tenpn

3

Cách tiếp cận vòng lặp sẽ làm việc tốt trong tuy nhiên clojure vòng/tái phát là được coi là hoạt động ở mức độ thấp và các hàm bậc cao hơn thường được ưu tiên.

Thông thường loại này của vấn đề sẽ được giải quyết bằng cách tạo ra một chuỗi các thẻ (nhân vật trong ví dụ của bạn) và áp dụng trên hoặc nhiều chức năng clojure của chuỗi (doseq, dorun, cất trong khi, vv)

Các ví dụ sau đây đọc tên người dùng đầu tiên từ/etc/passwd trên unix giống như các hệ thống.

(require '[clojure.java [io :as io]]) 

(defn char-seq 
    "create a lazy sequence of characters from an input stream" 
    [i-stream] 
    (map char 
    (take-while 
    (partial not= -1) 
    (repeatedly #(.read i-stream))))) 

;; process the sequence one token at a time 
;; with-open will automatically close the stream for us 

(with-open [is (io/input-stream "/etc/passwd")] 
    (doseq [c (take-while (partial not= \:) (char-seq is))] 
    ;; your processing is done here 
    (prn c))) 
0

tôi đi ra với phiên bản này:

(defn read-until 
    [^java.io.Reader rdr ^String delim] 
    (let [^java.lang.StringBuilder salida (StringBuilder.) ] 
    (while 
     (not (.endsWith (.toString salida) delim)) 
     (.append salida (str (char (.read rdr)))) 
    ) 
    (.toString salida) 
) 
) 

Có vẻ cho một String, không phải là một char duy nhất là delimiter!

Cảm ơn!