2010-05-15 38 views
9

Tôi có một câu hỏi liên quan đến vòng lặp liều lượng lồng nhau. Trong hàm khởi đầu, một khi tôi tìm thấy câu trả lời, tôi đặt nguyên tử thành true, để xác nhận vòng lặp bên ngoài với: trong khi không thành công. Tuy nhiên có vẻ như nó không phá vỡ nó, và các vòng tiếp tục đi. Có gì sai với nó?Làm thế nào để thoát ra khỏi liều lồng nhau

Tôi cũng khá bối rối với việc sử dụng nguyên tử, refs, đại lý (Tại sao chúng có tên khác nhau cho các chức năng cập nhật khi cơ chế gần như giống nhau?), V.v. Bạn có thể sử dụng nguyên tử trong tình trạng này như một lá cờ? Rõ ràng tôi cần một biến như đối tượng để lưu trữ một trạng thái.

(def pentagonal-list (map (fn [a] (/ (* a (dec (* 3 a))) 2)) (iterate inc 1))) 


(def found (atom false)) 


(defn pentagonal? [a] 
    (let [y (/ (inc (Math/sqrt (inc (* 24 a)))) 6) 
     x (mod (* 10 y) 10)] 
    (if (zero? x) 
    true 
    false))) 


(defn both-pent? [a b] 
    (let [sum (+ b a) 
     diff (- a b)] 
    (if (and (pentagonal? sum) (pentagonal? diff)) 
     true 
     false))) 

(defn start [] 
(doseq [x pentagonal-list :while (false? @found)] 
    (doseq [y pentagonal-list :while (<= y x)] 
     (if (both-pent? x y) 
      (do 
      (reset! found true) 
      (println (- x y))))))) 

Trả lời

13

Ngay cả khi nguyên tử được thiết lập để true, phiên bản của bạn không thể ngừng chạy cho đến khi kết thúc doseq bên trong (cho đến khi y> x). Nó sẽ kết thúc vòng lặp ngoài khi vòng lặp bên trong kết thúc. Nó chấm dứt cuối cùng khi tôi chạy nó. Không chắc chắn những gì bạn đang nhìn thấy.

Bạn không cần hai số doseq để thực hiện việc này. Một doseq có thể xử lý hai seq cùng một lúc.

user> (doseq [x (range 0 2) y (range 3 6)] (prn [x y])) 
[0 3] 
[0 4] 
[0 5] 
[1 3] 
[1 4] 
[1 5] 

(Điều này cũng đúng của for.) Không có cơ chế để "phá vỡ" của doseqs lồng nhau mà tôi biết, ngoại trừ throw/catch, nhưng đó là thay vì bỏ thành ngữ. Bạn không cần các nguyên tử hoặc doseq cho điều này.

(def answers (filter (fn [[x y]] (both-pent? x y)) 
        (for [x pentagonal-list 
          y pentagonal-list :while (<= y x)] 
         [x y]))) 

Mã của bạn rất bắt buộc phải có phong cách. "Lặp lại các danh sách này, sau đó kiểm tra các giá trị, sau đó in một cái gì đó, sau đó dừng vòng lặp." Sử dụng các nguyên tử để kiểm soát như thế này không phải là rất thành ngữ trong Clojure.

Một cách chức năng hơn là lấy một danh sách seq (ngũ giác) và bọc nó trong các hàm biến nó thành các seq khác cho đến khi bạn nhận được một seq cung cấp cho bạn những gì bạn muốn. Trước tiên, tôi sử dụng for để chuyển hai bản sao của seq này thành một seq của các cặp trong đó y < = x. Sau đó, tôi sử dụng filter để biến seq thành một trong đó lọc ra các giá trị mà chúng tôi không quan tâm.

filterfor rất lười, vì vậy thao tác này sẽ ngừng chạy sau khi tìm thấy giá trị hợp lệ first, nếu có tất cả những gì bạn muốn. Điều này trả về hai số bạn muốn, và sau đó bạn có thể trừ chúng.

(apply - (first answers)) 

Hoặc bạn có thể bọc thêm hàm này vào map khác để tính toán sự khác biệt cho bạn.

(def answers2 (map #(apply - %) answers)) 
(first answers2) 

Có một số lợi thế để lập trình có chức năng theo cách này. Các seq được lưu trữ (nếu bạn giữ lên đầu như tôi làm ở đây), vì vậy một khi một giá trị được tính toán, nó ghi nhớ nó và bạn có thể truy cập nó ngay lập tức từ đó trở đi. Phiên bản của bạn không thể chạy lại mà không cần cài đặt lại nguyên tử, và sau đó sẽ phải tính lại mọi thứ. Với phiên bản của tôi, bạn có thể (take 5 answers) để nhận được 5 kết quả đầu tiên hoặc lập bản đồ kết quả để thực hiện những việc khác nếu bạn muốn. Bạn có thể doseq trên nó và in các giá trị. Vv ..

Tôi chắc chắn có những cách khác (có thể tốt hơn) để thực hiện việc này mà không cần sử dụng nguyên tử. Bạn thường nên tránh thay đổi tham chiếu trừ khi cần 100% trong Clojure.

Tên hàm để thay đổi nguyên tử/đại lý/refs có thể khác nhau vì cơ học không giống nhau. Tài liệu tham khảo được đồng bộ và được điều phối thông qua giao dịch. Đại lý không đồng bộ. Các nguyên tử đồng bộ và không đồng nhất. Tất cả chúng đều "thay đổi một tham chiếu", và có lẽ một số loại siêu chức năng hoặc macro có thể bọc chúng trong cùng một tên, nhưng điều đó sẽ che khuất thực tế rằng chúng đang làm những thứ khác nhau đáng kể dưới mui xe. Giải thích sự khác biệt hoàn toàn có lẽ nằm ngoài phạm vi của một bài SO để giải thích, nhưng http://clojure.org giải thích đầy đủ tất cả các sắc thái của sự khác biệt.

+0

Cảm ơn. Đã không nhận ra rằng tôi có thể làm "looping" trong một liều duy nhất/cho. Bí quyết với việc sử dụng đầu tiên trên danh sách ngũ giác bị lọc và phá hủy là rất tốt. – fizbin

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