2011-11-03 51 views
13

Tôi đã viết một hàm để tính toán sự khác biệt đối xứng của hai bộ (một trong những vấn đề trên trang web 4clojure). Chức năng này đã vượt qua các bài kiểm tra đơn vị, nhưng nó không sạch như tôi muốn, với điều kiện tôi có mã trùng lặp.Làm cách nào để xác định hàm trong một hàm trong Clojure và tham chiếu hàm đó?

(fn [x y] (set (concat 
    (keep-indexed #(if (nil? (get y %2)) %2) x) 
    (keep-indexed #(if (nil? (get x %2)) %2) y)))) 

Rõ ràng là tôi muốn một cái gì đó như:

(fn [x y] (set (concat (diff x y) (diff y x)))) 

Trường hợp chức năng khác được định nghĩa và tham chiếu "inline", nhưng tôi không biết làm thế nào để làm điều đó trong một khối fn.

+2

Bạn thực sự có thể thấy các câu trả lời của người khác về 4clojure (một khi bạn đã hoàn thành câu hỏi), điều này sẽ cho bạn biết cách bạn có thể dọn dẹp các nỗ lực của riêng mình. –

Trả lời

21

Sử dụng một let hoặc letfn:

(fn [x y] 
    (let [diff (... function body here ...)] 
    (set 
    (concat (diff x y) (diff y x))))) 
10

Một trong những tính năng mà làm cho Clojure một lisp (và một ngôn ngữ chức năng nói chung) là chức năng là lớp học đầu tiên điều trong Clojure đặc biệt họ là đối tượng. Khi bạn thực hiện một hàm với (defn name [arg] ...) nếu xây dựng hàm và sau đó lưu trữ nó trong một var để bạn có thể tìm thấy nó sau này từ bất cứ đâu trong chương trình của bạn. nó rất giống như thế này:

(def name (fn [arg] ...)) 

bây giờ tên có chứa chức năng có thể truy cập rộng rãi. Các hàm không cần phải được lưu trữ trong các vars, đặc biệt nếu chúng chỉ cần thiết trong hàm của bạn. Trong trường hợp đó, nó có ý nghĩa hơn để liên kết hàm với tên cục bộ như với câu trả lời của Matt Fenwick.

(let [name (fn [agr] ...)] ...) 

macro letfn làm cho điều này trở nên thanh lịch hơn. Phần quan trọng là phải hiểu rằng các hàm là Đối tượng được lưu trữ trong mọi thứ và bạn có thể chọn vùng chứa phù hợp với nhu cầu của mình.

+1

Tại sao bạn nói "Phần quan trọng là phải hiểu rằng các chức năng là ** Đối tượng ** được lưu trữ trong mọi thứ"? Nói "Object" có thể khiến ai đó nghĩ rằng bạn đang nói về các đối tượng theo nghĩa hướng đối tượng. Chữ thường "đối tượng", tôi nghĩ, có thể tốt hơn ở đây. (Tôi hiểu rằng Clojure được thực hiện trên JVM, nơi mà nhiều thứ được thực hiện như là các lớp và đối tượng OO, nhưng tôi không nghĩ rằng Clojurians mới nhất thiết cần phải suy nghĩ về các chi tiết thực hiện.) –

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