Re: Hash-map destructuring
On Wed, Jun 16, 2010 at 7:00 PM, Brian Carper wrote: > Given: > > (defn foo [x & {:as args}] [x args]) > (foo 1 :bar 2 :baz [:quux]) > => [1 {:bar 2, :baz [:quux]}] > > If I have those rest-arguments already in a map, what's the most > elegant way to call foo with them? > > (def args {:bar 2 :baz [:quux]}) > (foo 1 ?) > > I feel like I may be missing some simple way of doing it. I find > myself needing to do this pretty often, for example any time I have a > chain of functions calling each other that all take keyword arguments > on the end. > I would do it like this, a la Python: (defn foo [a b & {:keys [c d]}] (println a b c d)) (defn ** [m] (apply concat (vec m))) (apply foo 1 2 (** {:c 3 :d 4})) (apply apply [foo 1 2 (** {:c 3 :d 4})]) The problem with your apply* is that it's macro so it can't be used as an fn. David -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Hash-map destructuring
On Jun 25, 2:57 am, Chas Emerick wrote: > This is fairly simple: > > user=> (defn foo [& {:as args}] [args]) > #'user/foo > user=> (def m {:a 5 :b 6}) > #'user/m > user=> (apply foo (-> m seq flatten)) > [{:a 5, :b 6}] > > I'm not sure if it could be made easier, short of changing apply > (which I wouldn't think is reasonable). > > - Chas That was what I tried first, but it doesn't work. It flattens too much. Note that I have a vector as one of the map values in my example. --Brian -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Hash-map destructuring
On Jun 16, 2010, at 9:21 PM, Michael Gardner wrote: On Jun 16, 2010, at 7:07 PM, ataggart wrote: There's a disconnect between the function definition and the datastructures used by the caller. Either fix the data structure: (def args [:bar 2 :baz [:quux]]) then use apply Or change the function definition to take a map: (defn foo [x {:keys [bar baz]}] ...) That's a pretty flippant answer. I have run into this same issue; it's not always desirable to have your function take a map, and if you get the data structure from elsewhere (say loaded from a config file), then you have to resort to either re-building the arg list manually or doing (apply concat ...). Regarding Brian's original question: as far as I know, there is no built-in version of apply that works with keyword args contained in a map. But note that you can eliminate the call to seq, since (apply concat args) works the same as (apply concat (seq args)). This is fairly simple: user=> (defn foo [& {:as args}] [args]) #'user/foo user=> (def m {:a 5 :b 6}) #'user/m user=> (apply foo (-> m seq flatten)) [{:a 5, :b 6}] I'm not sure if it could be made easier, short of changing apply (which I wouldn't think is reasonable). - Chas -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Hash-map destructuring
On Jun 16, 2010, at 7:07 PM, ataggart wrote: > There's a disconnect between the function definition and the > datastructures used by the caller. > > Either fix the data structure: > (def args [:bar 2 :baz [:quux]]) > then use apply > > Or change the function definition to take a map: > (defn foo [x {:keys [bar baz]}] > ...) That's a pretty flippant answer. I have run into this same issue; it's not always desirable to have your function take a map, and if you get the data structure from elsewhere (say loaded from a config file), then you have to resort to either re-building the arg list manually or doing (apply concat ...). Regarding Brian's original question: as far as I know, there is no built-in version of apply that works with keyword args contained in a map. But note that you can eliminate the call to seq, since (apply concat args) works the same as (apply concat (seq args)). -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Hash-map destructuring
There's a disconnect between the function definition and the datastructures used by the caller. Either fix the data structure: (def args [:bar 2 :baz [:quux]]) then use apply Or change the function definition to take a map: (defn foo [x {:keys [bar baz]}] ...) On Jun 16, 4:00 pm, Brian Carper wrote: > Given: > > (defn foo [x & {:as args}] [x args]) > (foo 1 :bar 2 :baz [:quux]) > => [1 {:bar 2, :baz [:quux]}] > > If I have those rest-arguments already in a map, what's the most > elegant way to call foo with them? > > (def args {:bar 2 :baz [:quux]}) > (foo 1 ?) > > I feel like I may be missing some simple way of doing it. I find > myself needing to do this pretty often, for example any time I have a > chain of functions calling each other that all take keyword arguments > on the end. > > (apply foo 1 (apply concat (seq args))) works, but that's awfully > nasty. So this is what I've been doing: > > (defmacro apply* [& args] > `(apply ~@(butlast args) (apply concat (seq ~(last args) > > (apply* foo 1 args) > => [1 {:bar 2, :baz [:quux]}] > > Kind of hacky though. Is there a better/shorter/builtin way? > > I can go back to using [x & args] in the function signature and (apply > hash-map args) in the function body, but I love having the keyword > destructuring in the function signature, since the user can see which > keys are valid to pass in, whenever I use {:keys [...]}. > > Thanks > --Brian -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Hash-map destructuring
Given: (defn foo [x & {:as args}] [x args]) (foo 1 :bar 2 :baz [:quux]) => [1 {:bar 2, :baz [:quux]}] If I have those rest-arguments already in a map, what's the most elegant way to call foo with them? (def args {:bar 2 :baz [:quux]}) (foo 1 ?) I feel like I may be missing some simple way of doing it. I find myself needing to do this pretty often, for example any time I have a chain of functions calling each other that all take keyword arguments on the end. (apply foo 1 (apply concat (seq args))) works, but that's awfully nasty. So this is what I've been doing: (defmacro apply* [& args] `(apply ~@(butlast args) (apply concat (seq ~(last args) (apply* foo 1 args) => [1 {:bar 2, :baz [:quux]}] Kind of hacky though. Is there a better/shorter/builtin way? I can go back to using [x & args] in the function signature and (apply hash-map args) in the function body, but I love having the keyword destructuring in the function signature, since the user can see which keys are valid to pass in, whenever I use {:keys [...]}. Thanks --Brian -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en