2011-11-03 9 views
13

Napisałem funkcję do obliczenia symetrycznej różnicy dwóch zestawów (jeden z problemów na stronie 4clojure). Funkcja przeszła testy jednostkowe, ale nie jest tak czysta, jak bym chciał, biorąc pod uwagę, że mam zduplikowany kod.Jak zdefiniować funkcję w funkcji w Clojure i odwołać się do tej funkcji?

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

Oczywiście wolałbym coś takiego:

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

Jeżeli funkcja diff jest zdefiniowany i odwoływać "inline", ale nie wiem, jak to zrobić w jednym bloku fn.

+2

Możesz zobaczyć odpowiedzi innych ludzi na 4clojure (po wypełnieniu pytania), które powinny dać ci wyobrażenie o tym, jak możesz uporządkować swoje własne próby. –

Odpowiedz

21

Użyj let lub letfn:

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

Jedną z cech, które sprawia, że ​​Clojure LISP (i język funkcjonalny w ogóle) jest to, że funkcje są pierwszej klasy rzeczy w Clojure specjalnie one są obiektami. Po utworzeniu funkcji z (defn name [arg] ...), jeśli kompiluje funkcję, a następnie zapisuje ją w var, dzięki czemu można ją później znaleźć w dowolnym miejscu w programie. to bardzo dużo:

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

teraz nazwa zawiera funkcję, która jest szeroko dostępna. Funkcje nie muszą być przechowywane w partiach, zwłaszcza jeśli są one potrzebne tylko w ramach funkcji. W takim przypadku bardziej sensowne jest powiązanie funkcji z lokalną nazwą, tak jak w przypadku odpowiedzi Matta Fenwicka.

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

letfn makro sprawia, że ​​to bardziej eleganckie. Ważną częścią jest zrozumienie, że funkcje są obiektami, które są przechowywane w rzeczach, i możesz wybrać pojemnik, który odpowiada Twoim potrzebom.

+1

Dlaczego powiedziałeś "Ważną częścią jest zrozumienie, że funkcje to ** Obiekty **, które są przechowywane w rzeczach"? Mówienie "Obiekt" może sprawić, że ktoś pomyśli, że mówisz o przedmiotach w sensie obiektowym. Małe "obiekty", jak sądzę, mogą być lepsze tutaj. (Rozumiem, że Clojure jest implementowane w maszynie JVM, w której wiele rzeczy jest wdrażanych jako klasy i obiekty OO, ale nie sądzę, aby nowi członkowie zespołu Clojurians musieli koniecznie myśleć o szczegółach implementacji.) –

Powiązane problemy