Re: Hash-map destructuring

2010-06-25 Thread David Nolen
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

2010-06-25 Thread Brian Carper
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

2010-06-25 Thread Chas Emerick


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

2010-06-16 Thread Michael Gardner
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

2010-06-16 Thread ataggart
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

2010-06-16 Thread Brian Carper
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