2013-10-15 13 views
11

Rozważmy funkcję z następującym podpisem:Clojure stosowania mapie i argumentów kluczowych zniszczenie

(defn make-widget [& {:keys [x y] :or {x 10 y 20}}] 
...) 

Jaki jest najlepszy sposób, aby przejść do mapy do funkcji, np

(make-widget {:x 100}) 

lub

(make-widget {:y 200 :x 0}) 

Co mam aktualnie myśli jest poprzez vec, flatten i apply np .:

(apply make-widget (flatten (vec ({:x 100})) 

Jestem przekonany, że istnieje lepszy sposób na zrobienie tego. Czy możesz rozważyć jeden?

Odpowiedz

10

Nie mogę wymyślić bardziej eleganckiego sposobu, chociaż wydaje mi się, że powinien być taki (jak na przykład specyficzny dla mapy wariant apply).

Ma problemy, które nie są zbyt eleganckie. Jeśli wartości twojej mapy są kolekcjami, flatten będzie działać rekurencyjnie także nad tymi, więc wszystko może się kompletnie pomieszać. Ten alternatywny unika tego problemu:

(apply make-widget (apply concat {:x 100})) 
+0

Funkcja mapply, opisana w odpowiedzi noncom, jest standardowym sposobem wykonania tej czynności. –

6

można użyć:

(apply make-widget (mapcat identity {:x 200 :y 0})) 
8

Jest też znana (nie wynaleziono przynajmniej przeze mnie), funkcja "mapply":

(defn mapply [f & args] (apply f (apply concat (butlast args) (last args)))) 

który może być stosowany, jak

(mapply your-function {:your "map"}) 

Dlaczego ta specyficzna dla języka funkcjonalność nie jest obecna w rdzeniu Clojure, a jest wdrażana bardziej natywnie i elegancko, nikt nie może dać mi jasnej odpowiedzi.

UPDATE

Po Spędziłem dużo czasu programowanie w Clojure, ja osobiście tendencję do powstrzymania się od tworzenia funkcji, które akceptują {} jako vararg. Chociaż na początku może się to wydawać atrakcyjne, w rzeczywistości doświadczenie dowodzi, że podawanie wyraźnej wartości jest zawsze lepsze z wielu powodów.

+1

Wszędobylskie mapply zostało dogodnie spakowane dla nas na https://github.com/ToBeReplaced/mapply. Po prostu dodaj [org.tobereplaced/mapply "1.0.0"] do swoich zależności project.clj. –

Powiązane problemy