2013-02-14 28 views
15

ngày khác tôi đang cố gắng đưa ra một ví dụ về đóng cửa trong Clojure. Tôi đã đưa ra và ví dụ tôi đã thấy trước đây và nghĩ rằng nó là thích hợp.Đóng cửa Clojure

Than ôi, tôi được cho biết đó không phải là một điều tốt và tôi nên cung cấp một cái gì đó cho phép.

Có ai có thể làm sáng tỏ không?

(defn pow [x n] (apply * (repeat x n))) 
(defn sq [y] (pow y 2)) 
(defn qb [y] (pow y 3)) 

Trả lời

20

Một đóng cửa là một chức năng có quyền truy cập vào một số tên giá trị/biến bên ngoài phạm vi riêng của mình, vì vậy từ một phạm vi cao hơn xung quanh các chức năng khi nó được tạo ra (điều này không bao gồm các đối số chức năng và giá trị tên địa phương tạo bên trong chức năng). Ví dụ của bạn không đủ điều kiện, bởi vì mọi chức năng chỉ sử dụng các giá trị được đặt tên từ phạm vi của riêng chúng.

Ví dụ:

(def foo 
    (let [counter (atom 0)] 
    (fn [] (do (swap! counter inc) @counter)))) 

(foo) ;;=> 1 
(foo) ;;=> 2 
(foo) ;;=> 3, etc 

Bây giờ foo là một hàm trả về giá trị của một nguyên tử nằm ngoài phạm vi của nó. Vì hàm vẫn giữ nguyên tham chiếu đến nguyên tử đó, nguyên tử sẽ không bị thu gom rác miễn là cần foo.

14

Chức năng trả về hàm tức là các hàm bậc cao hơn là ví dụ đẹp về đóng.

(defn pow [n] 
    (fn [x] (apply * (repeat n x)))) 

(def sq (pow 2)) 
(def qb (pow 3)) 
+0

Hi, vì vậy ví dụ của tôi sẽ là một đóng cửa nếu tôi đã xác định cơ thể của pow của tôi như bạn đã làm (đóng cửa là anon f)? – Eddy

+0

Có, đó là một cách để mô tả việc đóng cửa – Ankur

+0

+1 Ví dụ thanh lịch! –

3

Ví dụ khác về đóng cửa. Có hai chức năng chia sẻ cùng một môi trường (state).

(defn create-object [init-state] 
    (let [state (atom init-state)] 
    {:getter (fn [] 
       @state) 
    :setter (fn [new-val] 
       (reset! state new-val))})) 

(defn test-it [] 
    (let [{:keys [setter getter]} (create-object :init-value)] 
    (println (getter)) 
    (setter :new-value) 
    (println (getter)))) 

(test-it) 
=> :init-value 
    :new-value 
+1

cảm ơn, một ví dụ tuyệt vời!) – Eddy

-1

Tôi muốn có thứ gì đó thiết lập (các) giá trị không đổi sẽ được sử dụng mỗi lần.

(def myran 
    (let [constrand (rand)] 
    (fn [n] (* n constrand)))) 


(myran 3) 
2.7124521745892096 
(myran 1) 
0.9041507248630699 
(myran 3) 
2.7124521745892096 

Điều này sẽ chỉ đặt giá trị cho "constrand" một lần. Đây là một ví dụ rất giả tạo, nhưng tôi muốn để có thể làm điều gì đó như:

JavaScript: The Good Parts

này từ: JavaScript: The Good Parts